This commit was generated by cvs2svn to compensate for changes in r517,
authorMarc Fiuczynski <mef@cs.princeton.edu>
Mon, 7 Feb 2005 21:51:36 +0000 (21:51 +0000)
committerMarc Fiuczynski <mef@cs.princeton.edu>
Mon, 7 Feb 2005 21:51:36 +0000 (21:51 +0000)
which included commits to RCS files with non-trunk default branches.

2352 files changed:
Documentation/00-INDEX
Documentation/DocBook/Makefile
Documentation/DocBook/deviceiobook.tmpl
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/librs.tmpl [new file with mode: 0644]
Documentation/DocBook/mtdnand.tmpl [new file with mode: 0644]
Documentation/DocBook/procfs-guide.tmpl
Documentation/IO-mapping.txt
Documentation/RCU/listRCU.txt
Documentation/arm/Booting
Documentation/arm/IXP2000
Documentation/arm/IXP4xx
Documentation/arm/README
Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
Documentation/arm/Samsung-S3C24XX/Overview.txt
Documentation/arm/Samsung-S3C24XX/Suspend.txt [new file with mode: 0644]
Documentation/arm/Sharp-LH/IOBarrier
Documentation/block/as-iosched.txt
Documentation/block/biodoc.txt
Documentation/block/deadline-iosched.txt
Documentation/cdrom/00-INDEX
Documentation/cdrom/packet-writing.txt [new file with mode: 0644]
Documentation/computone.txt
Documentation/cpqarray.txt
Documentation/cpu-freq/cpufreq-nforce2.txt [new file with mode: 0644]
Documentation/cpu-freq/user-guide.txt
Documentation/crypto/api-intro.txt
Documentation/digiepca.txt
Documentation/dnotify.txt
Documentation/dvb/README.dibusb [new file with mode: 0644]
Documentation/dvb/avermedia.txt
Documentation/dvb/cards.txt
Documentation/dvb/contributors.txt
Documentation/dvb/get_dvb_firmware [new file with mode: 0644]
Documentation/dvb/readme.txt
Documentation/dvb/ttusb-dec.txt
Documentation/dvb/udev.txt [new file with mode: 0644]
Documentation/fb/matroxfb.txt
Documentation/filesystems/Locking
Documentation/filesystems/devfs/ChangeLog
Documentation/filesystems/devfs/README
Documentation/filesystems/ext2.txt
Documentation/filesystems/ufs.txt
Documentation/filesystems/vfs.txt
Documentation/floppy.txt
Documentation/ftape.txt
Documentation/hw_random.txt
Documentation/i2c/dev-interface
Documentation/i2c/i2c-stub [new file with mode: 0644]
Documentation/i2c/sysfs-interface
Documentation/i2c/writing-clients
Documentation/ia64/serial.txt [new file with mode: 0644]
Documentation/ibm-acpi.txt [new file with mode: 0644]
Documentation/ide.txt
Documentation/ioctl/cdrom.txt [new file with mode: 0644]
Documentation/ioctl/hdio.txt [new file with mode: 0644]
Documentation/kbuild/makefiles.txt
Documentation/kbuild/modules.txt
Documentation/keys.txt [new file with mode: 0644]
Documentation/memory.txt
Documentation/networking/e100.txt
Documentation/networking/e1000.txt
Documentation/networking/ixgb.txt
Documentation/networking/proc_net_tcp.txt [new file with mode: 0644]
Documentation/nmi_watchdog.txt
Documentation/parisc/registers
Documentation/pm.txt
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/ramdisk.txt
Documentation/rocket.txt
Documentation/s390/monreader.txt [new file with mode: 0644]
Documentation/s390/s390dbf.txt
Documentation/scsi/ChangeLog.megaraid
Documentation/scsi/sym53c8xx_2.txt
Documentation/seclvl.txt [new file with mode: 0644]
Documentation/sonypi.txt
Documentation/sound/alsa/Joystick.txt
Documentation/sound/oss/README.modules
Documentation/stable_api_nonsense.txt [new file with mode: 0644]
Documentation/time_interpolators.txt
Documentation/tipar.txt
Documentation/tty.txt
Documentation/usb/gadget_serial.txt [new file with mode: 0644]
Documentation/usb/silverlink.txt
Documentation/usb/sn9c102.txt
Documentation/usb/usb-serial.txt
Documentation/video4linux/meye.txt
Documentation/vm/overcommit-accounting
Documentation/x86_64/boot-options.txt
arch/alpha/boot/bootloader.lds
arch/alpha/boot/bootp.c
arch/alpha/boot/bootpz.c
arch/alpha/boot/head.S
arch/alpha/boot/misc.c
arch/alpha/kernel/alpha_ksyms.c
arch/alpha/kernel/console.c
arch/alpha/kernel/pci.c
arch/alpha/kernel/pci_impl.h
arch/alpha/kernel/srmcons.c
arch/alpha/kernel/sys_alcor.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_eb64p.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_mikasa.c
arch/alpha/kernel/sys_nautilus.c
arch/alpha/kernel/sys_noritake.c
arch/alpha/kernel/sys_rx164.c
arch/alpha/kernel/sys_titan.c
arch/alpha/kernel/sys_wildfire.c
arch/alpha/lib/dec_and_lock.c
arch/arm/Kconfig.debug
arch/arm/common/amba.c
arch/arm/common/icst307.c [new file with mode: 0644]
arch/arm/common/locomo.c
arch/arm/common/rtctime.c [new file with mode: 0644]
arch/arm/common/time-acorn.c
arch/arm/configs/bast_defconfig
arch/arm/configs/ep80219_defconfig
arch/arm/configs/integrator_defconfig
arch/arm/configs/iq31244_defconfig
arch/arm/configs/iq80321_defconfig
arch/arm/configs/iq80331_defconfig
arch/arm/configs/pleb_defconfig
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/simpad_defconfig [new file with mode: 0644]
arch/arm/configs/versatile_defconfig
arch/arm/kernel/fiq.c
arch/arm/kernel/io.c
arch/arm/kernel/module.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/Makefile
arch/arm/lib/csumpartial.S
arch/arm/lib/csumpartialcopygeneric.S
arch/arm/lib/delay.S
arch/arm/lib/getuser.S
arch/arm/lib/io-readsl.S [new file with mode: 0644]
arch/arm/lib/io-writesl.S
arch/arm/lib/longlong.h
arch/arm/lib/putuser.S
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/Kconfig
arch/arm/mach-footbridge/Makefile.boot [new file with mode: 0644]
arch/arm/mach-footbridge/cats-hw.c
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/netwinder-hw.c
arch/arm/mach-footbridge/personal.c [new file with mode: 0644]
arch/arm/mach-footbridge/time.c
arch/arm/mach-h720x/Kconfig
arch/arm/mach-h720x/Makefile.boot [new file with mode: 0644]
arch/arm/mach-h720x/common.h [new file with mode: 0644]
arch/arm/mach-h720x/cpu-h7201.c
arch/arm/mach-h720x/cpu-h7202.c
arch/arm/mach-h720x/h7201-eval.c
arch/arm/mach-h720x/h7202-eval.c
arch/arm/mach-imx/Makefile.boot [new file with mode: 0644]
arch/arm/mach-imx/generic.h
arch/arm/mach-imx/mx1ads.c
arch/arm/mach-imx/time.c
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
arch/arm/mach-iop3xx/Makefile.boot [new file with mode: 0644]
arch/arm/mach-iop3xx/common.c
arch/arm/mach-iop3xx/iop321-setup.c
arch/arm/mach-iop3xx/iop331-setup.c
arch/arm/mach-iop3xx/iop331-time.c
arch/arm/mach-ixp2000/Makefile.boot [new file with mode: 0644]
arch/arm/mach-ixp2000/core.c
arch/arm/mach-ixp2000/enp2611.c
arch/arm/mach-ixp2000/ixdp2400.c
arch/arm/mach-ixp2000/ixdp2800.c
arch/arm/mach-ixp2000/ixdp2x00.c
arch/arm/mach-ixp2000/ixdp2x01.c
arch/arm/mach-ixp2000/pci.c
arch/arm/mach-ixp4xx/Kconfig
arch/arm/mach-ixp4xx/Makefile
arch/arm/mach-ixp4xx/Makefile.boot [new file with mode: 0644]
arch/arm/mach-ixp4xx/common-pci.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-ixp4xx/ixdpg425-pci.c [new file with mode: 0644]
arch/arm/mach-ixp4xx/prpmc1100-setup.c
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-lh7a40x/time.c
arch/arm/mach-omap/Kconfig
arch/arm/mach-omap/Makefile.boot [new file with mode: 0644]
arch/arm/mach-omap/board-h2.c
arch/arm/mach-omap/board-h3.c
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/common.c
arch/arm/mach-omap/mcbsp.c
arch/arm/mach-omap/mux.c
arch/arm/mach-omap/ocpi.c
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/time.c
arch/arm/mach-omap/usb.c
arch/arm/mach-pxa/Makefile.boot [new file with mode: 0644]
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/ssp.c [new file with mode: 0644]
arch/arm/mach-pxa/time.c
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
arch/arm/mach-s3c2410/clock.h
arch/arm/mach-s3c2410/cpu.c
arch/arm/mach-s3c2410/cpu.h
arch/arm/mach-s3c2410/devs.c
arch/arm/mach-s3c2410/dma.c
arch/arm/mach-s3c2410/gpio.c
arch/arm/mach-s3c2410/irq.c
arch/arm/mach-s3c2410/mach-rx3715.c [new file with mode: 0644]
arch/arm/mach-s3c2410/mach-smdk2410.c
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
arch/arm/mach-s3c2410/s3c2440.c
arch/arm/mach-s3c2410/s3c2440.h
arch/arm/mach-s3c2410/sleep.S [new file with mode: 0644]
arch/arm/mach-s3c2410/time.c
arch/arm/mach-s3c2410/usb-simtec.c
arch/arm/mach-sa1100/Makefile.boot [new file with mode: 0644]
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/leds-simpad.c
arch/arm/mach-sa1100/neponset.c
arch/arm/mach-sa1100/pm.c
arch/arm/mach-sa1100/sleep.S
arch/arm/mach-sa1100/time.c
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/copypage-v6.c
arch/arm/mm/proc-arm720.S
arch/arm/mm/proc-v6.S
arch/arm/nwfpe/double_cpdo.c
arch/arm/vfp/vfp.h
arch/arm/vfp/vfpdouble.c
arch/arm/vfp/vfphw.S
arch/arm/vfp/vfpsingle.c
arch/arm26/kernel/time.c
arch/arm26/machine/dma.c
arch/arm26/machine/small_page.c
arch/cris/Kconfig.debug
arch/cris/arch-v10/kernel/Makefile
arch/cris/arch-v10/kernel/crisksyms.c [new file with mode: 0644]
arch/cris/arch-v10/kernel/irq.c
arch/cris/arch-v10/kernel/kgdb.c
arch/cris/arch-v10/vmlinux.lds.S
arch/h8300/kernel/time.c
arch/h8300/platform/h8s/edosk2674/crt0_rom.S
arch/i386/crypto/aes-i586-asm.S
arch/i386/kernel/acpi/Makefile
arch/i386/kernel/acpi/earlyquirk.c [new file with mode: 0644]
arch/i386/kernel/cpu/cpufreq/Kconfig
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/cpufreq/speedstep-lib.c
arch/i386/kernel/cpu/cyrix.c
arch/i386/kernel/cpu/intel_cacheinfo.c [new file with mode: 0644]
arch/i386/kernel/cpu/mcheck/mce.c
arch/i386/kernel/cpu/mcheck/mce.h
arch/i386/kernel/cpu/mtrr/main.c
arch/i386/kernel/cpu/nexgen.c
arch/i386/kernel/cpu/transmeta.c
arch/i386/kernel/kprobes.c
arch/i386/kernel/quirks.c [new file with mode: 0644]
arch/i386/kernel/semaphore.c
arch/i386/kernel/time.c
arch/i386/kernel/timers/common.c
arch/i386/kernel/timers/timer_cyclone.c
arch/i386/kernel/timers/timer_hpet.c
arch/i386/kernel/timers/timer_pit.c
arch/i386/lib/dec_and_lock.c
arch/i386/mach-es7000/es7000plat.c
arch/i386/mm/mmap.c
arch/i386/pci/common.c
arch/i386/pci/i386.c
arch/ia64/configs/bigsur_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/hp/sim/simeth.c
arch/ia64/hp/sim/simserial.c
arch/ia64/ia32/elfcore32.h
arch/ia64/kernel/domain.c [new file with mode: 0644]
arch/ia64/kernel/mca_asm.S
arch/ia64/kernel/sys_ia64.c
arch/ia64/lib/bitop.c
arch/ia64/lib/dec_and_lock.c
arch/ia64/lib/io.c
arch/ia64/lib/swiotlb.c
arch/ia64/mm/numa.c
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
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
arch/m32r/Kconfig.debug [new file with mode: 0644]
arch/m32r/Makefile
arch/m32r/boot/compressed/Makefile
arch/m32r/boot/compressed/head.S
arch/m32r/boot/compressed/m32r_sio.c
arch/m32r/boot/compressed/misc.c
arch/m32r/boot/compressed/vmlinux.lds.S
arch/m32r/boot/compressed/vmlinux.scr
arch/m32r/boot/setup.S
arch/m32r/defconfig
arch/m32r/kernel/io_m32700ut.c
arch/m32r/kernel/io_mappi.c
arch/m32r/kernel/io_mappi2.c
arch/m32r/kernel/io_oaks32r.c
arch/m32r/kernel/io_opsput.c
arch/m32r/kernel/io_usrv.c
arch/m32r/kernel/irq.c
arch/m32r/kernel/process.c
arch/m32r/kernel/ptrace.c
arch/m32r/kernel/setup_m32700ut.c
arch/m32r/kernel/setup_mappi.c
arch/m32r/kernel/setup_mappi2.c
arch/m32r/kernel/setup_opsput.c
arch/m32r/kernel/smpboot.c
arch/m32r/kernel/sys_m32r.c
arch/m32r/kernel/time.c
arch/m32r/lib/delay.c
arch/m32r/lib/memset.S
arch/m32r/m32700ut/defconfig.m32700ut.smp
arch/m32r/m32700ut/defconfig.m32700ut.up
arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB
arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB
arch/m32r/m32700ut/dot.gdbinit_400MHz_32MB [new file with mode: 0644]
arch/m32r/mappi/defconfig.nommu
arch/m32r/mappi/defconfig.smp
arch/m32r/mappi/defconfig.up
arch/m32r/mappi/dot.gdbinit
arch/m32r/mappi/dot.gdbinit.nommu
arch/m32r/mappi/dot.gdbinit.smp
arch/m32r/mappi2/defconfig.vdec2 [new file with mode: 0644]
arch/m32r/mappi2/dot.gdbinit.vdec2 [new file with mode: 0644]
arch/m32r/mm/init.c
arch/m32r/oaks32r/defconfig.nommu
arch/m32r/oaks32r/dot.gdbinit.nommu
arch/m32r/opsput/defconfig.opsput
arch/m32r/opsput/dot.gdbinit
arch/m68k/atari/hades-pci.c
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/m68k/hp300/config.c
arch/m68k/hp300/reboot.S
arch/m68k/hp300/time.c
arch/m68k/kernel/time.c
arch/m68k/kernel/vmlinux.lds.S
arch/m68k/sun3/Makefile
arch/m68knommu/Makefile
arch/m68knommu/defconfig
arch/m68knommu/kernel/module.c
arch/m68knommu/kernel/signal.c
arch/m68knommu/kernel/syscalltable.S
arch/m68knommu/kernel/time.c
arch/m68knommu/kernel/vmlinux.lds.S
arch/m68knommu/lib/Makefile
arch/m68knommu/lib/delay.c [new file with mode: 0644]
arch/m68knommu/mm/init.c
arch/m68knommu/mm/memory.c
arch/m68knommu/platform/5206e/MOTOROLA/crt0_ram.S
arch/m68knommu/platform/5206e/config.c
arch/m68knommu/platform/5249/config.c
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/5272/config.c
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/Makefile
arch/m68knommu/platform/5307/config.c
arch/m68knommu/platform/5307/pit.c [new file with mode: 0644]
arch/m68knommu/platform/5307/vectors.c
arch/m68knommu/platform/5407/config.c
arch/mips/arc/identify.c
arch/mips/arc/misc.c
arch/mips/au1000/common/au1xxx_irqmap.c
arch/mips/au1000/common/cputable.c
arch/mips/au1000/common/dbdma.c
arch/mips/au1000/common/dma.c
arch/mips/au1000/common/irq.c
arch/mips/au1000/common/pci.c
arch/mips/au1000/common/platform.c [new file with mode: 0644]
arch/mips/au1000/common/puts.c
arch/mips/au1000/common/reset.c
arch/mips/au1000/common/time.c
arch/mips/au1000/common/usbdev.c
arch/mips/au1000/csb250/irqmap.c
arch/mips/au1000/db1x00/board_setup.c
arch/mips/au1000/db1x00/irqmap.c
arch/mips/au1000/db1x00/mirage_ts.c
arch/mips/au1000/hydrogen3/board_setup.c
arch/mips/au1000/hydrogen3/irqmap.c
arch/mips/au1000/mtx-1/irqmap.c
arch/mips/au1000/pb1000/board_setup.c
arch/mips/au1000/pb1000/irqmap.c
arch/mips/au1000/pb1100/board_setup.c
arch/mips/au1000/pb1100/irqmap.c
arch/mips/au1000/pb1500/board_setup.c
arch/mips/au1000/pb1500/irqmap.c
arch/mips/au1000/pb1550/board_setup.c
arch/mips/au1000/pb1550/irqmap.c
arch/mips/au1000/xxs1500/board_setup.c
arch/mips/au1000/xxs1500/irqmap.c
arch/mips/boot/addinitrd.c
arch/mips/cobalt/irq.c
arch/mips/cobalt/setup.c
arch/mips/configs/db1550_defconfig [new file with mode: 0644]
arch/mips/configs/ocelot_3_defconfig [new file with mode: 0644]
arch/mips/configs/ocelot_g_defconfig
arch/mips/ddb5xxx/common/Makefile
arch/mips/ddb5xxx/ddb5074/nile4_pic.c
arch/mips/ddb5xxx/ddb5074/setup.c
arch/mips/ddb5xxx/ddb5476/setup.c
arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c
arch/mips/ddb5xxx/ddb5477/irq_5477.c
arch/mips/ddb5xxx/ddb5477/setup.c
arch/mips/dec/boot/decstation.c
arch/mips/dec/setup.c
arch/mips/galileo-boards/ev96100/irq.c
arch/mips/galileo-boards/ev96100/time.c
arch/mips/gt64120/ev64120/irq.c
arch/mips/gt64120/momenco_ocelot/dbg_io.c
arch/mips/gt64120/momenco_ocelot/irq.c
arch/mips/ite-boards/generic/irq.c
arch/mips/jazz/irq.c
arch/mips/jazz/jazzdma.c
arch/mips/jazz/reset.c
arch/mips/jmr3927/rbhma3100/setup.c
arch/mips/kernel/gdb-stub.c
arch/mips/kernel/genex.S
arch/mips/kernel/head.S
arch/mips/kernel/i8259.c
arch/mips/kernel/ioctl32.c
arch/mips/kernel/irq-msc01.c [new file with mode: 0644]
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/vmlinux.lds.S
arch/mips/lasat/interrupt.c
arch/mips/lasat/setup.c
arch/mips/lib-64/dump_tlb.c
arch/mips/lib/csum_partial_copy.c
arch/mips/lib/dec_and_lock.c
arch/mips/lib/strlen_user.S
arch/mips/lib/strnlen_user.S
arch/mips/math-emu/cp1emu.c
arch/mips/mips-boards/atlas/atlas_int.c
arch/mips/mips-boards/atlas/atlas_setup.c
arch/mips/mips-boards/generic/init.c
arch/mips/mips-boards/generic/memory.c
arch/mips/mips-boards/generic/pci.c
arch/mips/mips-boards/malta/malta_int.c
arch/mips/mips-boards/malta/malta_setup.c
arch/mips/mips-boards/sead/sead_int.c
arch/mips/mips-boards/sead/sead_setup.c
arch/mips/mm/c-r3k.c
arch/mips/mm/c-r4k.c
arch/mips/mm/c-sb1.c
arch/mips/mm/c-tx39.c
arch/mips/mm/ioremap.c
arch/mips/mm/pg-r4k.c
arch/mips/mm/pgtable-64.c
arch/mips/mm/tlb-andes.c
arch/mips/mm/tlb-r3k.c
arch/mips/mm/tlb-r4k.c
arch/mips/mm/tlb-r8k.c
arch/mips/mm/tlbex.c [new file with mode: 0644]
arch/mips/mm/tlbex32-mips32.S [new file with mode: 0644]
arch/mips/mm/tlbex32-r3k.S
arch/mips/mm/tlbex32-r4k.S
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/momentum/ocelot_c/dbg_io.c
arch/mips/momentum/ocelot_g/dbg_io.c
arch/mips/momentum/ocelot_g/irq.c
arch/mips/pci/fixup-atlas.c
arch/mips/pci/fixup-cobalt.c
arch/mips/pci/fixup-ddb5074.c
arch/mips/pci/fixup-ddb5477.c
arch/mips/pci/fixup-ev96100.c
arch/mips/pci/fixup-ip32.c
arch/mips/pci/fixup-ite8172g.c
arch/mips/pci/fixup-ivr.c
arch/mips/pci/fixup-jmr3927.c
arch/mips/pci/fixup-malta.c
arch/mips/pci/fixup-mpc30x.c
arch/mips/pci/fixup-ocelot3.c [new file with mode: 0644]
arch/mips/pci/fixup-rbtx4927.c
arch/mips/pci/fixup-sni.c
arch/mips/pci/ops-it8172.c
arch/mips/pci/ops-tx3927.c
arch/mips/pci/ops-tx4927.c
arch/mips/pci/pci-ddb5074.c
arch/mips/pci/pci-ddb5476.c
arch/mips/pci/pci-ddb5477.c
arch/mips/pci/pci-ev96100.c
arch/mips/pci/pci-ip27.c
arch/mips/pci/pci-ip32.c
arch/mips/pci/pci-jmr3927.c
arch/mips/pci/pci-lasat.c
arch/mips/pci/pci-sb1250.c
arch/mips/pci/pci-yosemite.c
arch/mips/pmc-sierra/yosemite/smp.c
arch/mips/sgi-ip22/ip22-berr.c
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip27/ip27-init.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-klnuma.c
arch/mips/sgi-ip27/ip27-memory.c
arch/mips/sgi-ip27/ip27-smp.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sgi-ip32/crime.c
arch/mips/sgi-ip32/ip32-reset.c
arch/mips/sgi-ip32/ip32-setup.c
arch/mips/sibyte/cfe/setup.c
arch/mips/sibyte/cfe/smp.c
arch/mips/sibyte/sb1250/prom.c
arch/mips/sibyte/swarm/setup.c
arch/mips/sni/irq.c
arch/mips/sni/setup.c
arch/mips/tx4927/common/Makefile
arch/mips/tx4927/common/tx4927_setup.c
arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
arch/parisc/hpux/fs.c
arch/parisc/install.sh [new file with mode: 0644]
arch/parisc/kernel/parisc_ksyms.c
arch/parisc/kernel/pdc_cons.c
arch/parisc/kernel/perf_asm.S
arch/parisc/kernel/perf_images.h
arch/parisc/kernel/time.c
arch/parisc/kernel/topology.c [new file with mode: 0644]
arch/parisc/kernel/unaligned.c
arch/parisc/kernel/unwind.c
arch/parisc/lib/Makefile
arch/parisc/lib/checksum.c
arch/parisc/lib/debuglocks.c
arch/parisc/lib/fixup.S [new file with mode: 0644]
arch/parisc/lib/lusercopy.S
arch/parisc/lib/memcpy.c [new file with mode: 0644]
arch/parisc/mm/fault.c
arch/ppc/8xx_io/Kconfig
arch/ppc/8xx_io/Makefile
arch/ppc/8xx_io/fec.c
arch/ppc/8xx_io/micropatch.c
arch/ppc/Kconfig.debug
arch/ppc/boot/common/util.S
arch/ppc/boot/lib/Makefile
arch/ppc/boot/simple/misc-embedded.c
arch/ppc/boot/simple/mpc52xx_tty.c
arch/ppc/boot/utils/mkbugboot.c
arch/ppc/configs/FADS_defconfig
arch/ppc/configs/IVMS8_defconfig
arch/ppc/configs/SM850_defconfig
arch/ppc/configs/SPD823TS_defconfig
arch/ppc/configs/TQM823L_defconfig
arch/ppc/configs/TQM850L_defconfig
arch/ppc/configs/TQM860L_defconfig
arch/ppc/configs/bseip_defconfig
arch/ppc/configs/mbx_defconfig
arch/ppc/configs/rpxcllf_defconfig
arch/ppc/configs/rpxlite_defconfig
arch/ppc/kernel/bitops.c
arch/ppc/kernel/head_8xx.S
arch/ppc/kernel/head_booke.h
arch/ppc/kernel/head_e500.S
arch/ppc/kernel/pci.c
arch/ppc/kernel/ppc_htab.c
arch/ppc/kernel/softemu8xx.c
arch/ppc/lib/dec_and_lock.c
arch/ppc/lib/rheap.c
arch/ppc/mm/44x_mmu.c
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/85xx/mpc8555.c
arch/ppc/platforms/85xx/mpc8560_ads.c
arch/ppc/platforms/85xx/mpc85xx_ads_common.c
arch/ppc/platforms/85xx/mpc85xx_cds_common.c
arch/ppc/platforms/85xx/sbc85xx.c
arch/ppc/platforms/adir_pic.c
arch/ppc/platforms/chrp_pci.c
arch/ppc/platforms/chrp_setup.c
arch/ppc/platforms/gemini_pci.c
arch/ppc/platforms/k2.c
arch/ppc/platforms/lopec.c
arch/ppc/platforms/mcpn765.c
arch/ppc/platforms/mvme5100.c
arch/ppc/platforms/pcore.c
arch/ppc/platforms/pmac_pci.c
arch/ppc/platforms/pmac_smp.c
arch/ppc/platforms/prep_pci.c
arch/ppc/platforms/prpmc750.c
arch/ppc/platforms/rpxclassic.h
arch/ppc/platforms/rpxlite.h
arch/ppc/platforms/tqm8xx.h
arch/ppc/syslib/gen550.h [new file with mode: 0644]
arch/ppc/syslib/gen550_dbg.c
arch/ppc/syslib/gen550_kgdb.c
arch/ppc/syslib/i8259.c
arch/ppc/syslib/ibm440gx_common.c
arch/ppc/syslib/ibm440gx_common.h
arch/ppc/syslib/ibm44x_common.c
arch/ppc/syslib/indirect_pci.c
arch/ppc/syslib/mpc52xx_setup.c
arch/ppc/syslib/ppc4xx_dma.c
arch/ppc/syslib/ppc4xx_setup.c
arch/ppc/syslib/ppc8xx_pic.c
arch/ppc/syslib/prom.c
arch/ppc/syslib/todc_time.c
arch/ppc/syslib/xilinx_pic.c [new file with mode: 0644]
arch/ppc/xmon/start.c
arch/ppc/xmon/xmon.c
arch/ppc64/Kconfig.debug
arch/ppc64/configs/maple_defconfig [new file with mode: 0644]
arch/ppc64/kernel/i8259.c
arch/ppc64/kernel/i8259.h
arch/ppc64/kernel/iSeries_iommu.c
arch/ppc64/kernel/iSeries_irq.c
arch/ppc64/kernel/iSeries_smp.c [new file with mode: 0644]
arch/ppc64/kernel/iomap.c
arch/ppc64/kernel/lmb.c
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/mf.c
arch/ppc64/kernel/mpic.c [new file with mode: 0644]
arch/ppc64/kernel/mpic.h [new file with mode: 0644]
arch/ppc64/kernel/nvram.c
arch/ppc64/kernel/pSeries_iommu.c
arch/ppc64/kernel/pSeries_setup.c
arch/ppc64/kernel/pSeries_smp.c [new file with mode: 0644]
arch/ppc64/kernel/pci_iommu.c
arch/ppc64/kernel/pmac.h
arch/ppc64/kernel/pmac_low_i2c.c
arch/ppc64/kernel/pmac_pci.c
arch/ppc64/kernel/pmac_setup.c
arch/ppc64/kernel/proc_ppc64.c
arch/ppc64/kernel/prom_init.c
arch/ppc64/kernel/u3_iommu.c
arch/ppc64/kernel/vecemu.c
arch/ppc64/lib/dec_and_lock.c
arch/ppc64/lib/sstep.c [new file with mode: 0644]
arch/ppc64/mm/hash_native.c
arch/ppc64/mm/mmap.c
arch/ppc64/oprofile/op_impl.h
arch/ppc64/xmon/start.c
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/cpcmd.c
arch/s390/kernel/irq.c
arch/s390/mm/extmem.c
arch/sh/boards/bigsur/irq.c
arch/sh/boards/bigsur/setup.c
arch/sh/boards/dreamcast/setup.c
arch/sh/boards/harp/setup.c
arch/sh/boards/overdrive/pcidma.c
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/renesas/rts7751r2d/mach.c
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/se/770x/irq.c
arch/sh/boards/se/770x/mach.c
arch/sh/boards/se/7751/io.c
arch/sh/boards/se/7751/pci.c
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/rts7751r2d_defconfig
arch/sh/configs/se73180_defconfig [new file with mode: 0644]
arch/sh/configs/se7705_defconfig [new file with mode: 0644]
arch/sh/configs/se7751_defconfig
arch/sh/configs/sh03_defconfig [new file with mode: 0644]
arch/sh/drivers/dma/dma-g2.c
arch/sh/drivers/dma/dma-pvr2.c
arch/sh/drivers/pci/dma-dreamcast.c
arch/sh/drivers/pci/fixups-dreamcast.c
arch/sh/drivers/pci/fixups-rts7751r2d.c
arch/sh/drivers/pci/fixups-sh03.c [new file with mode: 0644]
arch/sh/drivers/pci/ops-rts7751r2d.c
arch/sh/drivers/pci/ops-sh03.c [new file with mode: 0644]
arch/sh/drivers/pci/pci-st40.c
arch/sh/drivers/pci/pci-st40.h
arch/sh/kernel/asm-offsets.c [new file with mode: 0644]
arch/sh/kernel/cpu/irq_imask.c
arch/sh/kernel/cpu/sh2/Makefile
arch/sh/kernel/cpu/sh2/probe.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/Makefile
arch/sh/kernel/cpu/sh3/probe.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4/Makefile
arch/sh/kernel/cpu/sh4/ex.S
arch/sh/kernel/cpu/sh4/irq_intc2.c
arch/sh/kernel/cpu/sh4/probe.c [new file with mode: 0644]
arch/sh/kernel/early_printk.c
arch/sh/kernel/sh_bios.c
arch/sh/kernel/signal.c
arch/sh/lib/Makefile
arch/sh/lib/memcpy-sh4.S [new file with mode: 0644]
arch/sh/mm/Makefile
arch/sh/mm/cache-sh2.c
arch/sh/mm/cache-sh7705.c [new file with mode: 0644]
arch/sh/mm/extable.c
arch/sh/mm/ioremap.c
arch/sh/mm/pg-sh7705.c [new file with mode: 0644]
arch/sh/oprofile/Makefile
arch/sh/oprofile/op_model_sh7750.c [new file with mode: 0644]
arch/sh/ramdisk/Makefile
arch/sh/tools/Makefile
arch/sh/tools/gen-mach-types [new file with mode: 0644]
arch/sh64/kernel/irq.c
arch/sh64/kernel/irq_intc.c
arch/sh64/kernel/pci_sh5.c
arch/sh64/kernel/process.c
arch/sh64/kernel/ptrace.c
arch/sh64/kernel/time.c
arch/sparc/kernel/auxio.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/pcic.c
arch/sparc/kernel/pmc.c
arch/sparc/lib/bitext.c
arch/sparc/mm/generic.c
arch/sparc/mm/srmmu.c
arch/sparc64/kernel/binfmt_elf32.c
arch/sparc64/kernel/isa.c
arch/sparc64/kernel/kprobes.c
arch/sparc64/kernel/pci_iommu.c
arch/sparc64/kernel/trampoline.S
arch/sparc64/lib/dec_and_lock.S
arch/sparc64/mm/generic.c
arch/sparc64/solaris/entry64.S
arch/sparc64/solaris/systbl.S
arch/um/Makefile-x86_64 [new file with mode: 0644]
arch/um/drivers/cow_user.c
arch/um/include/frame_kern.h
arch/um/include/mode.h
arch/um/include/mode_kern.h
arch/um/include/ptrace_user.h
arch/um/include/syscall_user.h
arch/um/include/um_mmu.h
arch/um/kernel/dyn.lds.S
arch/um/kernel/main.c
arch/um/kernel/signal_user.c
arch/um/kernel/skas/exec_kern.c
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/syscall_user.c
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/tt.h
arch/um/kernel/tt/include/uaccess-tt.h [new file with mode: 0644]
arch/um/kernel/uml.lds.S
arch/um/sys-i386/ptrace.c
arch/um/sys-i386/sysrq.c
arch/v850/kernel/memcons.c
arch/v850/kernel/rte_mb_a_pci.c
arch/v850/kernel/signal.c
arch/v850/kernel/simcons.c
arch/x86_64/Kconfig.debug
arch/x86_64/boot/Makefile
arch/x86_64/boot/compressed/Makefile
arch/x86_64/kernel/cpufreq/Kconfig
arch/x86_64/kernel/cpufreq/Makefile
arch/x86_64/kernel/early_printk.c
arch/x86_64/kernel/entry.S
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/kernel/nmi.c
arch/x86_64/kernel/vsyscall.c
arch/x86_64/lib/bitops.c
arch/x86_64/lib/bitstr.c
arch/x86_64/lib/dec_and_lock.c
arch/x86_64/mm/k8topology.c
crypto/anubis.c [new file with mode: 0644]
crypto/blowfish.c
crypto/serpent.c
crypto/sha256.c
crypto/sha512.c
drivers/acorn/block/fd1772.c
drivers/acpi/Makefile
drivers/acpi/dispatcher/dsmthdat.c
drivers/acpi/dispatcher/dsutils.c
drivers/acpi/dispatcher/dswexec.c
drivers/acpi/dispatcher/dswload.c
drivers/acpi/dispatcher/dswstate.c
drivers/acpi/events/evgpe.c
drivers/acpi/events/evgpeblk.c
drivers/acpi/events/evxfevnt.c
drivers/acpi/events/evxfregn.c
drivers/acpi/executer/exconvrt.c
drivers/acpi/executer/exdump.c
drivers/acpi/executer/exfldio.c
drivers/acpi/executer/exmisc.c
drivers/acpi/executer/exoparg1.c
drivers/acpi/executer/exprep.c
drivers/acpi/executer/exregion.c
drivers/acpi/executer/exresolv.c
drivers/acpi/executer/exresop.c
drivers/acpi/executer/exstore.c
drivers/acpi/executer/exsystem.c
drivers/acpi/executer/exutils.c
drivers/acpi/hardware/Makefile
drivers/acpi/hardware/hwgpe.c
drivers/acpi/hardware/hwregs.c
drivers/acpi/hardware/hwsleep.c
drivers/acpi/hardware/hwtimer.c
drivers/acpi/ibm_acpi.c [new file with mode: 0644]
drivers/acpi/motherboard.c
drivers/acpi/namespace/Makefile
drivers/acpi/namespace/nsaccess.c
drivers/acpi/namespace/nsdump.c
drivers/acpi/namespace/nseval.c
drivers/acpi/namespace/nsinit.c
drivers/acpi/namespace/nsnames.c
drivers/acpi/namespace/nssearch.c
drivers/acpi/namespace/nsutils.c
drivers/acpi/namespace/nsxfeval.c
drivers/acpi/namespace/nsxfname.c
drivers/acpi/namespace/nsxfobj.c
drivers/acpi/parser/psopcode.c
drivers/acpi/parser/psparse.c
drivers/acpi/parser/pstree.c
drivers/acpi/parser/psutils.c
drivers/acpi/pci_bind.c
drivers/acpi/resources/Makefile
drivers/acpi/resources/rscalc.c
drivers/acpi/resources/rsutils.c
drivers/acpi/resources/rsxface.c
drivers/acpi/sleep/Makefile
drivers/acpi/sleep/poweroff.c
drivers/acpi/sleep/proc.c
drivers/acpi/sleep/sleep.h
drivers/acpi/sleep/wakeup.c
drivers/acpi/tables/tbget.c
drivers/acpi/tables/tbinstal.c
drivers/acpi/tables/tbutils.c
drivers/acpi/tables/tbxface.c
drivers/acpi/tables/tbxfroot.c
drivers/acpi/utilities/utalloc.c
drivers/acpi/utilities/utcopy.c
drivers/acpi/utilities/utdebug.c
drivers/acpi/utilities/utdelete.c
drivers/acpi/utilities/utmath.c
drivers/acpi/utilities/utmisc.c
drivers/acpi/utilities/utobject.c
drivers/acpi/utilities/utxface.c
drivers/acpi/utils.c
drivers/acpi/video.c [new file with mode: 0644]
drivers/atm/Makefile
drivers/atm/ambassador.h
drivers/atm/atmtcp.c
drivers/atm/eni.c
drivers/atm/horizon.h
drivers/atm/iphase.h
drivers/atm/nicstar.c
drivers/atm/zatm.c
drivers/block/Kconfig.iosched
drivers/block/amiflop.c
drivers/block/noop-iosched.c
drivers/block/pktcdvd.c [new file with mode: 0644]
drivers/block/ub.c
drivers/block/z2ram.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_vhci.c
drivers/cdrom/Makefile
drivers/cdrom/sbpcd.c
drivers/char/agp/frontend.c
drivers/char/amiserial.c
drivers/char/ds1302.c [new file with mode: 0644]
drivers/char/ec3104_keyb.c
drivers/char/epca.c
drivers/char/epca.h
drivers/char/ftape/lowlevel/ftape-ctl.c
drivers/char/ftape/lowlevel/ftape-io.c
drivers/char/ftape/zftape/zftape-buffers.c
drivers/char/generic_serial.c
drivers/char/hpet.c
drivers/char/hvc_console.c
drivers/char/hvcs.c
drivers/char/i8k.c
drivers/char/ip2.c
drivers/char/isicom.c
drivers/char/mmtimer.c
drivers/char/mxser.h [new file with mode: 0644]
drivers/char/nwflash.c
drivers/char/pcxx.c
drivers/char/qtronix.c
drivers/char/rio/rio_linux.c
drivers/char/riscom8.c
drivers/char/s3c2410-rtc.c [new file with mode: 0644]
drivers/char/serial167.c
drivers/char/snsc.c
drivers/char/specialix.c
drivers/char/sx.c
drivers/char/sx.h
drivers/char/synclink.c
drivers/char/tpqic02.c
drivers/char/viocons.c
drivers/char/watchdog/ixp2000_wdt.c
drivers/char/watchdog/ixp4xx_wdt.c
drivers/char/watchdog/s3c2410_wdt.c [new file with mode: 0644]
drivers/cpufreq/Kconfig
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_performance.c
drivers/cpufreq/cpufreq_powersave.c
drivers/cpufreq/freq_table.c
drivers/dio/Makefile
drivers/dio/dio-driver.c [new file with mode: 0644]
drivers/dio/dio-sysfs.c [new file with mode: 0644]
drivers/dio/dio.c
drivers/eisa/eisa-bus.c
drivers/fc4/soc.c
drivers/fc4/soc.h
drivers/fc4/socal.c
drivers/fc4/socal.h
drivers/firmware/pcdp.c
drivers/i2c/algos/i2c-algo-ite.c
drivers/i2c/algos/i2c-algo-pca.c
drivers/i2c/busses/i2c-amd756-s4882.c [new file with mode: 0644]
drivers/i2c/busses/i2c-hydra.c
drivers/i2c/busses/i2c-i810.c
drivers/i2c/busses/i2c-ibm_iic.h
drivers/i2c/busses/i2c-ite.c
drivers/i2c/busses/i2c-keywest.h
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-prosavage.c
drivers/i2c/busses/i2c-s3c2410.c [new file with mode: 0644]
drivers/i2c/busses/i2c-savage4.c
drivers/i2c/busses/i2c-stub.c [new file with mode: 0644]
drivers/i2c/chips/adm1025.c
drivers/i2c/chips/adm1026.c [new file with mode: 0644]
drivers/i2c/chips/adm1031.c
drivers/i2c/chips/ds1621.c
drivers/i2c/chips/lm63.c [new file with mode: 0644]
drivers/i2c/chips/lm77.c
drivers/i2c/chips/lm87.c [new file with mode: 0644]
drivers/i2c/chips/max1619.c
drivers/i2c/chips/pc87360.c [new file with mode: 0644]
drivers/i2c/chips/pcf8574.c
drivers/i2c/chips/pcf8591.c
drivers/i2c/chips/smsc47m1.c
drivers/i2c/i2c-sensor-detect.c
drivers/ide/arm/icside.c
drivers/ide/arm/rapide.c
drivers/ide/cris/Makefile [new file with mode: 0644]
drivers/ide/cris/ide-v10.c [new file with mode: 0644]
drivers/ide/ide-default.c
drivers/ide/ide-lib.c
drivers/ide/legacy/Makefile
drivers/ide/legacy/ali14xx.c
drivers/ide/legacy/dtc2278.c
drivers/ide/legacy/ht6560b.c
drivers/ide/legacy/qd65xx.c
drivers/ide/legacy/qd65xx.h
drivers/ide/legacy/umc8672.c
drivers/ide/pci/cy82c693.c
drivers/ide/pci/hpt34x.c
drivers/ide/ppc/pmac.c
drivers/ieee1394/ohci1394.c
drivers/ieee1394/pcilynx.c
drivers/ieee1394/pcilynx.h
drivers/ieee1394/sbp2.h
drivers/input/gameport/fm801-gp.c
drivers/input/joystick/amijoy.c
drivers/input/joystick/db9.c
drivers/input/joystick/gamecon.c
drivers/input/joystick/turbografx.c
drivers/input/mouse/pc110pad.c
drivers/input/serio/q40kbd.c
drivers/input/serio/rpckbd.c
drivers/input/serio/serio.c
drivers/isdn/divert/divert_init.c
drivers/isdn/divert/divert_procfs.c
drivers/isdn/divert/isdn_divert.c
drivers/isdn/divert/isdn_divert.h
drivers/isdn/hardware/avm/Kconfig
drivers/isdn/hardware/avm/c4.c
drivers/isdn/hardware/eicon/diva_pci.h
drivers/isdn/hardware/eicon/io.c
drivers/isdn/hardware/eicon/io.h
drivers/isdn/hardware/eicon/platform.h
drivers/isdn/hardware/eicon/s_4bri.c
drivers/isdn/hardware/eicon/s_bri.c
drivers/isdn/hardware/eicon/s_pri.c
drivers/isdn/hardware/eicon/xdi_adapter.h
drivers/isdn/hisax/amd7930_fn.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/hfc_sx.c
drivers/isdn/hisax/hfcscard.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/hisax_fcpcipnp.c
drivers/isdn/hisax/isurf.c
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/telespci.c
drivers/isdn/hysdn/boardergo.c
drivers/isdn/hysdn/hycapi.c
drivers/isdn/hysdn/hysdn_sched.c
drivers/isdn/i4l/Kconfig
drivers/isdn/i4l/isdn_bsdcomp.c
drivers/isdn/icn/icn.h
drivers/isdn/sc/card.h
drivers/isdn/sc/init.c
drivers/isdn/tpam/tpam_main.c
drivers/isdn/tpam/tpam_nco.c
drivers/isdn/tpam/tpam_queues.c
drivers/macintosh/ans-lcd.c
drivers/macintosh/macio-adb.c
drivers/macintosh/macserial.c
drivers/macintosh/therm_pm72.h
drivers/macintosh/therm_windtunnel.c
drivers/macintosh/via-cuda.c
drivers/macintosh/via-pmu.c
drivers/md/dm-crypt.c
drivers/md/dm-io.c
drivers/md/faulty.c [new file with mode: 0644]
drivers/md/raid0.c
drivers/media/Kconfig
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_hlp.c
drivers/media/common/saa7146_i2c.c
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/b2c2/Makefile
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/Kconfig
drivers/media/dvb/bt8xx/Makefile
drivers/media/dvb/bt8xx/bt878.c
drivers/media/dvb/bt8xx/bt878.h
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/bt8xx/dvb-bt8xx.h
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/dvb-core/Makefile
drivers/media/dvb/dvb-core/dvb_ca_en50221.h
drivers/media/dvb/dvb-core/dvb_filter.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/at76c651.c
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.c
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.c
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.c
drivers/media/dvb/frontends/mt312.h
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.c
drivers/media/dvb/frontends/nxt6000.h
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.c
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.c
drivers/media/dvb/frontends/ves1820.h [new file with mode: 0644]
drivers/media/dvb/frontends/ves1x93.c
drivers/media/dvb/frontends/ves1x93.h [new file with mode: 0644]
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/Makefile
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_hw.h
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget-core.c
drivers/media/dvb/ttpci/budget-patch.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttpci/budget.h
drivers/media/dvb/ttpci/ttpci-eeprom.c
drivers/media/dvb/ttpci/ttpci-eeprom.h
drivers/media/dvb/ttusb-budget/Kconfig
drivers/media/dvb/ttusb-budget/Makefile
drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h
drivers/media/dvb/ttusb-dec/Kconfig
drivers/media/dvb/ttusb-dec/Makefile
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/bt848.h
drivers/media/video/btcx-risc.c
drivers/media/video/btcx-risc.h
drivers/media/video/bttv-gpio.c
drivers/media/video/bttv-if.c
drivers/media/video/cx88/Makefile
drivers/media/video/cx88/cx88-blackbird.c [new file with mode: 0644]
drivers/media/video/cx88/cx88-core.c
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/msp3400.h
drivers/media/video/ovcamchip/ovcamchip_core.c
drivers/media/video/saa7134/Makefile
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/saa7134/saa7134-reg.h
drivers/media/video/saa7134/saa7134-vbi.c
drivers/media/video/saa7146.h
drivers/media/video/v4l2-common.c
drivers/media/video/video-buf-dvb.c [new file with mode: 0644]
drivers/media/video/zoran.h
drivers/message/i2o/debug.c
drivers/message/i2o/device.c
drivers/message/i2o/driver.c
drivers/message/i2o/exec-osm.c
drivers/message/i2o/iop.c
drivers/message/i2o/pci.c
drivers/misc/ibmasm/ibmasm.h
drivers/misc/ibmasm/lowlevel.c
drivers/misc/ibmasm/lowlevel.h
drivers/misc/ibmasm/uart.c
drivers/mmc/Kconfig
drivers/mmc/Makefile
drivers/mmc/mmc_block.c
drivers/mmc/mmc_queue.c
drivers/mmc/mmc_queue.h
drivers/mmc/mmci.c
drivers/mmc/mmci.h
drivers/mmc/pxamci.c
drivers/mmc/pxamci.h
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/chips/map_absent.c
drivers/mtd/devices/mtdram.c
drivers/mtd/devices/phram.c
drivers/mtd/devices/slram.c
drivers/mtd/maps/bast-flash.c [new file with mode: 0644]
drivers/mtd/maps/db1550-flash.c
drivers/mtd/maps/db1x00-flash.c
drivers/mtd/maps/dmv182.c
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/ipaq-flash.c [new file with mode: 0644]
drivers/mtd/maps/ixp2000.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/mpc1211.c
drivers/mtd/maps/ocotea.c [new file with mode: 0644]
drivers/mtd/maps/omap-toto-flash.c
drivers/mtd/maps/pb1550-flash.c
drivers/mtd/maps/ts5500_flash.c [new file with mode: 0644]
drivers/mtd/mtdblock_ro.c
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/h1910.c [new file with mode: 0644]
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/ppchameleonevb.c
drivers/mtd/nand/rtc_from4.c [new file with mode: 0644]
drivers/mtd/nand/s3c2410.c [new file with mode: 0644]
drivers/mtd/nand/toto.c
drivers/mtd/nand/tx4925ndfmc.c
drivers/mtd/nand/tx4938ndfmc.c
drivers/net/3c515.c
drivers/net/7990.c
drivers/net/7990.h
drivers/net/8139cp.c
drivers/net/8390.c
drivers/net/a2065.c
drivers/net/acenic_firmware.h
drivers/net/amd8111e.c
drivers/net/amd8111e.h
drivers/net/appletalk/cops.c
drivers/net/ariadne.c
drivers/net/arm/am79c961a.c
drivers/net/arm/ether1.c
drivers/net/arm/ether3.c
drivers/net/atari_bionet.c
drivers/net/atari_pamsnet.c
drivers/net/atarilance.c
drivers/net/atp.c
drivers/net/au1000_eth.c
drivers/net/bagetlance.c
drivers/net/bonding/bonding.h
drivers/net/bsd_comp.c
drivers/net/cris/Makefile [new file with mode: 0644]
drivers/net/cris/eth_v10.c [new file with mode: 0644]
drivers/net/declance.c
drivers/net/defxx.h
drivers/net/depca.c
drivers/net/dl2k.c
drivers/net/dl2k.h
drivers/net/e1000/e1000_osdep.h
drivers/net/ethertap.c
drivers/net/fec.c
drivers/net/fec.h
drivers/net/fec_8xx/fec_8xx-netta.c
drivers/net/fec_8xx/fec_main.c
drivers/net/fec_8xx/fec_mii.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/baycom_par.c
drivers/net/hamradio/mkiss.c
drivers/net/hamradio/scc.c
drivers/net/hamradio/yam.c
drivers/net/hplance.c
drivers/net/hplance.h
drivers/net/hydra.c
drivers/net/ibm_emac/ibm_emac_core.c
drivers/net/ibm_emac/ibm_emac_mal.h
drivers/net/irda/au1k_ir.c
drivers/net/irda/sa1100_ir.c
drivers/net/irda/vlsi_ir.h
drivers/net/mac8390.c
drivers/net/mac89x0.c
drivers/net/meth.c
drivers/net/mv643xx_eth.c
drivers/net/mvme147.c
drivers/net/myri_sbus.c
drivers/net/net_init.c
drivers/net/ni5010.c
drivers/net/ni65.c
drivers/net/ppp_deflate.c
drivers/net/rrunner.h
drivers/net/seeq8005.c
drivers/net/sk_g16.c
drivers/net/slip.c
drivers/net/smc91x.c
drivers/net/smc91x.h
drivers/net/sunbmac.c
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/net/tokenring/3c359.c
drivers/net/tokenring/abyss.c
drivers/net/tokenring/tmspci.c
drivers/net/tulip/xircom_cb.c
drivers/net/via-velocity.c
drivers/net/via-velocity.h
drivers/net/wan/cycx_drv.c
drivers/net/wan/cycx_main.c
drivers/net/wan/cycx_x25.c
drivers/net/wan/dlci.c
drivers/net/wan/hdlc_x25.c
drivers/net/wan/lapbether.c
drivers/net/wan/lmc/lmc_media.c
drivers/net/wan/pc300.h
drivers/net/wan/pc300_drv.c
drivers/net/wan/sdla.c
drivers/net/wan/sdla_chdlc.c
drivers/net/wireless/arlan.h
drivers/net/wireless/netwave_cs.c
drivers/net/wireless/wavelan.c
drivers/net/wireless/wavelan.p.h
drivers/net/wireless/wavelan_cs.c
drivers/net/wireless/wavelan_cs.p.h
drivers/net/wireless/wl3501_cs.c
drivers/net/znet.c
drivers/oprofile/timer_int.c
drivers/parisc/lba_pci.c
drivers/parisc/power.c
drivers/parisc/sba_iommu.c
drivers/parport/Kconfig
drivers/parport/parport_sunbpp.c
drivers/pci/bus.c
drivers/pci/hotplug/Makefile
drivers/pci/hotplug/acpiphp_ibm.c
drivers/pci/hotplug/cpqphp_nvram.c
drivers/pci/hotplug/cpqphp_nvram.h
drivers/pci/hotplug/fakephp.c
drivers/pci/hotplug/ibmphp_ebda.c
drivers/pci/msi.h
drivers/pci/pci-acpi.c [new file with mode: 0644]
drivers/pci/remove.c
drivers/pci/rom.c [new file with mode: 0644]
drivers/pci/setup-bus.c
drivers/pci/setup-irq.c
drivers/pci/setup-res.c
drivers/pcmcia/bulkmem.c
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/pcmcia/pxa2xx_base.c
drivers/pcmcia/pxa2xx_lubbock.c
drivers/pcmcia/yenta_socket.h
drivers/pnp/Kconfig
drivers/pnp/Makefile
drivers/pnp/interface.c
drivers/pnp/isapnp/Kconfig
drivers/pnp/manager.c
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/pnp/pnpbios/rsparser.c
drivers/pnp/quirks.c
drivers/pnp/resource.c
drivers/s390/block/dcssblk.c
drivers/s390/block/xpram.c
drivers/s390/char/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/monreader.c [new file with mode: 0644]
drivers/s390/char/sclp_tty.c
drivers/s390/char/sclp_vt220.c
drivers/s390/char/tape_block.c
drivers/s390/char/vmlogrdr.c [new file with mode: 0644]
drivers/s390/char/vmwatchdog.c [new file with mode: 0644]
drivers/s390/cio/css.h
drivers/s390/crypto/Makefile
drivers/s390/crypto/z90common.h
drivers/s390/crypto/z90crypt.h
drivers/s390/crypto/z90hardware.c
drivers/s390/crypto/z90main.c
drivers/s390/net/iucv.h
drivers/s390/scsi/zfcp_fsf.h
drivers/sbus/char/aurora.c
drivers/sbus/char/bbc_i2c.c
drivers/sbus/char/jsflash.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-9xxx.h
drivers/scsi/BusLogic.h
drivers/scsi/NCR5380.c
drivers/scsi/a100u2w.c [new file with mode: 0644]
drivers/scsi/a100u2w.h [new file with mode: 0644]
drivers/scsi/ahci.c
drivers/scsi/aic7xxx/aic79xx.h
drivers/scsi/aic7xxx/aic79xx.reg
drivers/scsi/aic7xxx/aic79xx_inline.h
drivers/scsi/aic7xxx/aic79xx_pci.h [new file with mode: 0644]
drivers/scsi/aic7xxx/aic7xxx.h
drivers/scsi/aic7xxx/aic7xxx_pci.c
drivers/scsi/aic7xxx/aic7xxx_pci.h [new file with mode: 0644]
drivers/scsi/aic7xxx/aiclib.h
drivers/scsi/aic7xxx/cam.h
drivers/scsi/dtc.h
drivers/scsi/ibmvscsi/rpa_vscsi.c
drivers/scsi/initio.c [new file with mode: 0644]
drivers/scsi/initio.h [new file with mode: 0644]
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/mac53c94.c
drivers/scsi/megaraid/megaraid_ioctl.h
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/megaraid/megaraid_mbox.h
drivers/scsi/megaraid/megaraid_mm.c
drivers/scsi/megaraid/megaraid_mm.h
drivers/scsi/mesh.c
drivers/scsi/osst.h
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/scsi/ql1040_fw.h [new file with mode: 0644]
drivers/scsi/ql12160_fw.h
drivers/scsi/ql1280_fw.h
drivers/scsi/qlogicfc_asm.c
drivers/scsi/sata_nv.c
drivers/scsi/sata_sx4.c
drivers/scsi/sata_uli.c
drivers/scsi/sym53c8xx_2/sym53c8xx.h
drivers/scsi/sym53c8xx_2/sym_conf.h
drivers/scsi/sym53c8xx_2/sym_defs.h
drivers/scsi/sym53c8xx_2/sym_fw.c
drivers/scsi/sym53c8xx_2/sym_fw.h
drivers/scsi/sym53c8xx_2/sym_fw1.h
drivers/scsi/sym53c8xx_2/sym_fw2.h
drivers/scsi/sym53c8xx_2/sym_glue.h
drivers/scsi/sym53c8xx_2/sym_hipd.c
drivers/scsi/sym53c8xx_2/sym_hipd.h
drivers/scsi/sym53c8xx_2/sym_malloc.c
drivers/scsi/sym53c8xx_2/sym_misc.c
drivers/scsi/sym53c8xx_2/sym_misc.h
drivers/scsi/sym53c8xx_2/sym_nvram.c
drivers/scsi/sym53c8xx_2/sym_nvram.h
drivers/scsi/t128.h
drivers/serial/21285.c
drivers/serial/68328serial.c
drivers/serial/8250.h
drivers/serial/8250_early.c [new file with mode: 0644]
drivers/serial/8250_gsc.c
drivers/serial/8250_hp300.c [new file with mode: 0644]
drivers/serial/amba-pl010.c
drivers/serial/clps711x.c
drivers/serial/cpm_uart/cpm_uart.h
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/cpm_uart/cpm_uart_cpm1.c
drivers/serial/crisv10.c [new file with mode: 0644]
drivers/serial/crisv10.h [new file with mode: 0644]
drivers/serial/dz.c
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/serial/mcfserial.c
drivers/serial/pmac_zilog.h
drivers/serial/s3c2410.c
drivers/serial/sa1100.c
drivers/serial/serial_cs.c
drivers/serial/serial_lh7a40x.c
drivers/serial/sn_console.c
drivers/serial/uart00.c
drivers/telephony/ixj_pcmcia.c
drivers/usb/atm/Kconfig [new file with mode: 0644]
drivers/usb/atm/speedtch.c
drivers/usb/atm/usb_atm.c
drivers/usb/atm/usb_atm.h
drivers/usb/class/Kconfig
drivers/usb/class/cdc-acm.h
drivers/usb/core/sysfs.c
drivers/usb/gadget/Makefile
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/goku_udc.h
drivers/usb/gadget/lh7a40x_udc.c
drivers/usb/gadget/net2280.h
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/omap_udc.h
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
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-lh7a404.c
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/image/Kconfig
drivers/usb/image/microtek.h
drivers/usb/input/pid.c
drivers/usb/input/touchkitusb.c
drivers/usb/input/usbkbd.c
drivers/usb/input/usbmouse.c
drivers/usb/input/xpad.c
drivers/usb/media/sn9c102.h
drivers/usb/media/sn9c102_core.c
drivers/usb/media/sn9c102_pas106b.c
drivers/usb/media/sn9c102_pas202bcb.c
drivers/usb/media/sn9c102_sensor.h
drivers/usb/media/sn9c102_tas5110c1b.c
drivers/usb/media/sn9c102_tas5130d1b.c
drivers/usb/misc/phidgetkit.c [new file with mode: 0644]
drivers/usb/misc/rio500.c
drivers/usb/misc/tiglusb.h
drivers/usb/net/Kconfig
drivers/usb/net/catc.c
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/io_fw_boot.h
drivers/usb/serial/io_fw_boot2.h
drivers/usb/serial/io_fw_down.h
drivers/usb/serial/io_fw_down2.h
drivers/usb/serial/io_tables.h
drivers/usb/serial/io_usbvend.h
drivers/usb/serial/ipw.c [new file with mode: 0644]
drivers/usb/storage/freecom.c
drivers/usb/storage/protocol.c
drivers/video/amifb.c
drivers/video/asiliantfb.c
drivers/video/aty/Makefile
drivers/video/aty/ati_ids.h
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb.h
drivers/video/aty/mach64_accel.c
drivers/video/aty/mach64_ct.c
drivers/video/aty/mach64_gx.c
drivers/video/aty/xlinit.c
drivers/video/bw2.c
drivers/video/cg14.c
drivers/video/cg3.c
drivers/video/cg6.c
drivers/video/chipsfb.c
drivers/video/console/bitblit.c [new file with mode: 0644]
drivers/video/console/font_6x11.c
drivers/video/console/tileblit.c [new file with mode: 0644]
drivers/video/controlfb.c
drivers/video/cyber2000fb.h
drivers/video/epson1355fb.c
drivers/video/fbsysfs.c
drivers/video/ffb.c
drivers/video/fm2fb.c
drivers/video/gbefb.c
drivers/video/hpfb.c
drivers/video/i810/i810.h
drivers/video/i810/i810_accel.c
drivers/video/i810/i810_main.c
drivers/video/igafb.c
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/kyro/STG4000InitDevice.c
drivers/video/kyro/STG4000Interface.h
drivers/video/kyro/STG4000OverlayDevice.c
drivers/video/kyro/STG4000Ramdac.c
drivers/video/kyro/STG4000Reg.h
drivers/video/kyro/STG4000VTG.c
drivers/video/leo.c
drivers/video/matrox/matroxfb_accel.c
drivers/video/matrox/matroxfb_crtc2.h
drivers/video/offb.c
drivers/video/p9100.c
drivers/video/platinumfb.c
drivers/video/pvr2fb.c
drivers/video/pxafb.c
drivers/video/riva/nv_driver.c
drivers/video/riva/riva_hw.h
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/video/sbuslib.c
drivers/video/sgivwfb.c
drivers/video/stifb.c
drivers/video/tcx.c
drivers/video/valkyriefb.c
drivers/w1/Kconfig
drivers/w1/Makefile
drivers/w1/dscore.c
drivers/w1/dscore.h
drivers/w1/matrox_w1.c
drivers/w1/w1.c
drivers/w1/w1.h
drivers/w1/w1_family.c
drivers/w1/w1_int.c
drivers/w1/w1_netlink.c
drivers/w1/w1_therm.c
drivers/zorro/zorro.c
fs/adfs/super.c
fs/afs/main.c
fs/autofs/inode.c
fs/cifs/Makefile
fs/cifs/cifs_fs_sb.h
fs/cifs/netmisc.c
fs/cifs/readdir.c [new file with mode: 0644]
fs/cifs/smberr.h
fs/cifs/xattr.c
fs/devfs/util.c
fs/efs/namei.c
fs/efs/super.c
fs/ext2/dir.c
fs/ext2/ext2.h
fs/fat/cache.c
fs/fat/misc.c
fs/filesystems.c
fs/hfs/Makefile
fs/hfs/attr.c [new file with mode: 0644]
fs/hfs/btree.c
fs/hfs/dir.c
fs/hfs/extent.c
fs/hfs/hfs_fs.h
fs/hfs/mdb.c
fs/hfsplus/btree.c
fs/hfsplus/extents.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/super.c
fs/jbd/checkpoint.c
fs/jffs2/dir.c
fs/jfs/jfs_dinode.h
fs/jfs/jfs_dmap.h
fs/jfs/jfs_dtree.h
fs/jfs/jfs_imap.h
fs/jfs/jfs_superblock.h
fs/jfs/jfs_unicode.c
fs/jfs/jfs_unicode.h
fs/jfs/jfs_xattr.h
fs/jfs/jfs_xtree.h
fs/libfs.c
fs/lockd/Makefile
fs/minix/bitmap.c
fs/msdos/namei.c
fs/nfsd/nfssvc.c
fs/ntfs/aops.h [new file with mode: 0644]
fs/ntfs/bitmap.c
fs/ntfs/index.c
fs/ntfs/index.h
fs/ntfs/lcnalloc.c
fs/ntfs/lcnalloc.h
fs/ntfs/quota.c
fs/ntfs/runlist.c [new file with mode: 0644]
fs/ntfs/runlist.h [new file with mode: 0644]
fs/partitions/devfs.c
fs/partitions/efi.c
fs/qnx4/bitmap.c
fs/reiserfs/resize.c
fs/sysv/CHANGES
fs/sysv/ChangeLog
fs/udf/balloc.c
fs/udf/file.c
fs/udf/lowlevel.c
fs/ufs/cylinder.c
fs/ufs/ialloc.c
fs/ufs/inode.c
fs/ufs/namei.c
fs/ufs/super.c
fs/ufs/util.c
fs/ufs/util.h
fs/xfs/linux-2.6/kmem.c
fs/xfs/linux-2.6/kmem.h
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_buf.h
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_globals.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/linux-2.6/xfs_lrw.c
fs/xfs/linux-2.6/xfs_sysctl.c
fs/xfs/linux-2.6/xfs_sysctl.h
fs/xfs/quota/xfs_qm.h
fs/xfs/quota/xfs_qm_bhv.c
fs/xfs/xfs_alloc.c
fs/xfs/xfs_iget.c
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_trans_inode.c
fs/xfs/xfs_utils.c
include/acpi/acconfig.h
include/acpi/acdebug.h
include/acpi/acdispat.h
include/acpi/acglobal.h
include/acpi/achware.h
include/acpi/acinterp.h
include/acpi/aclocal.h
include/acpi/acmacros.h
include/acpi/acnamesp.h
include/acpi/acobject.h
include/acpi/acparser.h
include/acpi/acpi_bus.h
include/acpi/acpixf.h
include/acpi/acresrc.h
include/acpi/actables.h
include/acpi/actbl.h
include/acpi/actypes.h
include/acpi/acutils.h
include/acpi/amlcode.h
include/acpi/amlresrc.h
include/acpi/platform/acenv.h
include/acpi/processor.h
include/asm-alpha/core_cia.h
include/asm-alpha/errno.h
include/asm-alpha/hardirq.h
include/asm-alpha/mmzone.h
include/asm-arm/arch-clps711x/io.h
include/asm-arm/arch-clps711x/time.h
include/asm-arm/arch-ebsa285/io.h
include/asm-arm/arch-epxa10db/io.h
include/asm-arm/arch-h720x/io.h
include/asm-arm/arch-imx/io.h
include/asm-arm/arch-integrator/io.h
include/asm-arm/arch-iop3xx/io.h
include/asm-arm/arch-ixp2000/dma.h
include/asm-arm/arch-ixp2000/io.h
include/asm-arm/arch-ixp2000/irqs.h
include/asm-arm/arch-ixp2000/ixdp2x00.h
include/asm-arm/arch-ixp2000/ixdp2x01.h
include/asm-arm/arch-ixp2000/ixp2000-regs.h
include/asm-arm/arch-ixp2000/platform.h
include/asm-arm/arch-ixp2000/system.h
include/asm-arm/arch-ixp4xx/io.h
include/asm-arm/arch-ixp4xx/platform.h
include/asm-arm/arch-l7200/io.h
include/asm-arm/arch-l7200/time.h
include/asm-arm/arch-lh7a40x/io.h
include/asm-arm/arch-lh7a40x/timex.h
include/asm-arm/arch-omap/board-h2.h
include/asm-arm/arch-omap/board-h3.h
include/asm-arm/arch-omap/board-innovator.h
include/asm-arm/arch-omap/board.h
include/asm-arm/arch-omap/cpu.h [new file with mode: 0644]
include/asm-arm/arch-omap/io.h
include/asm-arm/arch-omap/irqs.h
include/asm-arm/arch-omap/mcbsp.h
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/timex.h
include/asm-arm/arch-pxa/io.h
include/asm-arm/arch-pxa/ssp.h [new file with mode: 0644]
include/asm-arm/arch-rpc/io.h
include/asm-arm/arch-s3c2410/bast-pmu.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/dma.h
include/asm-arm/arch-s3c2410/hardware.h
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/regs-dsc.h
include/asm-arm/arch-s3c2410/regs-gpio.h
include/asm-arm/arch-s3c2410/regs-iic.h
include/asm-arm/arch-s3c2410/regs-lcd.h
include/asm-arm/arch-s3c2410/regs-rtc.h
include/asm-arm/arch-s3c2410/regs-sdi.h
include/asm-arm/arch-s3c2410/regs-udc.h
include/asm-arm/arch-s3c2410/regs-watchdog.h
include/asm-arm/arch-s3c2410/system.h
include/asm-arm/arch-s3c2410/timex.h
include/asm-arm/arch-s3c2410/uncompress.h
include/asm-arm/arch-sa1100/ide.h
include/asm-arm/arch-sa1100/io.h
include/asm-arm/arch-sa1100/system.h
include/asm-arm/arch-sa1100/timex.h
include/asm-arm/arch-shark/io.h
include/asm-arm/arch-versatile/hardware.h
include/asm-arm/arch-versatile/io.h
include/asm-arm/arch-versatile/platform.h
include/asm-arm/arch-versatile/timex.h
include/asm-arm/bitops.h
include/asm-arm/delay.h
include/asm-arm/hardirq.h
include/asm-arm/hardware/amba_clcd.h
include/asm-arm/hardware/icst307.h [new file with mode: 0644]
include/asm-arm/io.h
include/asm-arm/irq.h
include/asm-arm/mach/flash.h
include/asm-arm/mach/irda.h [new file with mode: 0644]
include/asm-arm/mach/irq.h
include/asm-arm/mach/map.h
include/asm-arm/mach/mmc.h
include/asm-arm/mach/time.h
include/asm-arm/mmu_context.h
include/asm-arm/posix_types.h
include/asm-arm/procinfo.h
include/asm-arm/rtc.h [new file with mode: 0644]
include/asm-arm/serial.h
include/asm-arm/tlbflush.h
include/asm-arm26/hardirq.h
include/asm-arm26/io.h
include/asm-cris/hardirq.h
include/asm-generic/dma-mapping-broken.h
include/asm-generic/errno.h
include/asm-generic/pci.h
include/asm-generic/topology.h
include/asm-h8300/delay.h
include/asm-h8300/signal.h
include/asm-h8300/system.h
include/asm-h8300/ucontext.h
include/asm-i386/hardirq.h
include/asm-i386/io.h
include/asm-i386/kprobes.h
include/asm-i386/mach-default/do_timer.h
include/asm-i386/mach-summit/mach_mpparse.h
include/asm-i386/mach-visws/do_timer.h
include/asm-i386/mach-voyager/do_timer.h
include/asm-i386/node.h
include/asm-i386/pci-direct.h [new file with mode: 0644]
include/asm-i386/semaphore.h
include/asm-i386/topology.h
include/asm-ia64/hardirq.h
include/asm-ia64/io.h
include/asm-ia64/machvec_init.h
include/asm-ia64/ptrace.h
include/asm-ia64/sn/l1.h [new file with mode: 0644]
include/asm-ia64/topology.h
include/asm-m32r/elf.h
include/asm-m32r/hardirq.h
include/asm-m32r/ide.h
include/asm-m32r/io.h
include/asm-m32r/m32102.h
include/asm-m32r/pgtable.h
include/asm-m32r/processor.h
include/asm-m32r/rtc.h
include/asm-m32r/termbits.h
include/asm-m32r/topology.h
include/asm-m68k/blinken.h
include/asm-m68k/hardirq.h
include/asm-m68k/hp300hw.h [new file with mode: 0644]
include/asm-m68k/mc146818rtc.h
include/asm-m68k/timex.h
include/asm-m68knommu/checksum.h
include/asm-m68knommu/coldfire.h
include/asm-m68knommu/delay.h
include/asm-m68knommu/hardirq.h
include/asm-m68knommu/io.h
include/asm-m68knommu/m527xsim.h [new file with mode: 0644]
include/asm-m68knommu/m528xsim.h [new file with mode: 0644]
include/asm-m68knommu/mcfdma.h
include/asm-m68knommu/mcfpit.h
include/asm-m68knommu/mcfsim.h
include/asm-m68knommu/mcfuart.h
include/asm-m68knommu/page_offset.h
include/asm-m68knommu/param.h
include/asm-m68knommu/system.h
include/asm-m68knommu/thread_info.h
include/asm-mips/addrspace.h
include/asm-mips/asmmacro-32.h
include/asm-mips/asmmacro-64.h
include/asm-mips/bitops.h
include/asm-mips/compat.h
include/asm-mips/compiler.h [new file with mode: 0644]
include/asm-mips/cpu-features.h
include/asm-mips/cpu-info.h [new file with mode: 0644]
include/asm-mips/debug.h
include/asm-mips/dec/serial.h [new file with mode: 0644]
include/asm-mips/delay.h
include/asm-mips/div64.h
include/asm-mips/dma-mapping.h
include/asm-mips/errno.h
include/asm-mips/fixmap.h
include/asm-mips/gdb-stub.h
include/asm-mips/hardirq.h
include/asm-mips/hw_irq.h
include/asm-mips/ide.h
include/asm-mips/interrupt.h [new file with mode: 0644]
include/asm-mips/io.h
include/asm-mips/ip32/crime.h
include/asm-mips/ip32/mace.h
include/asm-mips/irq.h
include/asm-mips/jazz.h
include/asm-mips/mach-atlas/mc146818rtc.h
include/asm-mips/mach-generic/floppy.h
include/asm-mips/mach-generic/mangle-port.h
include/asm-mips/mach-generic/spaces.h
include/asm-mips/mach-ip22/spaces.h [new file with mode: 0644]
include/asm-mips/mach-ip27/mangle-port.h
include/asm-mips/mach-ip27/mmzone.h
include/asm-mips/mach-ip27/spaces.h
include/asm-mips/mach-ip27/topology.h
include/asm-mips/mach-ip32/mangle-port.h
include/asm-mips/mach-ip32/spaces.h [new file with mode: 0644]
include/asm-mips/mach-ja/cpu-feature-overrides.h
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/mach-yosemite/cpu-feature-overrides.h
include/asm-mips/marvell.h
include/asm-mips/mmzone.h
include/asm-mips/msc01_ic.h [new file with mode: 0644]
include/asm-mips/numnodes.h
include/asm-mips/pci/bridge.h
include/asm-mips/posix_types.h
include/asm-mips/r4kcache.h
include/asm-mips/sgi/ioc.h
include/asm-mips/sgiarcs.h
include/asm-mips/siginfo.h
include/asm-mips/sim.h
include/asm-mips/sn/hub.h
include/asm-mips/sn/mapped_kernel.h
include/asm-mips/sn/sn_private.h
include/asm-mips/socket.h
include/asm-mips/statfs.h
include/asm-mips/tx4927/smsc_fdc37m81x.h [new file with mode: 0644]
include/asm-mips/tx4927/tx4927.h
include/asm-mips/war.h
include/asm-parisc/assembly.h
include/asm-parisc/bug.h
include/asm-parisc/errno.h
include/asm-parisc/hardirq.h
include/asm-parisc/io.h
include/asm-parisc/pci.h
include/asm-parisc/posix_types.h
include/asm-parisc/ptrace.h
include/asm-parisc/string.h
include/asm-parisc/superio.h
include/asm-parisc/thread_info.h
include/asm-parisc/tlbflush.h
include/asm-ppc/8xx_immap.h
include/asm-ppc/cputable.h
include/asm-ppc/hardirq.h
include/asm-ppc/hw_irq.h
include/asm-ppc/mpc85xx.h
include/asm-ppc/mpc8xx.h
include/asm-ppc/open_pic.h
include/asm-ppc/pci-bridge.h
include/asm-ppc/thread_info.h
include/asm-ppc/time.h
include/asm-ppc/timex.h
include/asm-ppc/xparameters.h [new file with mode: 0644]
include/asm-ppc64/floppy.h
include/asm-ppc64/iSeries/mf.h
include/asm-ppc64/plpar_wrappers.h
include/asm-ppc64/serial.h
include/asm-ppc64/sstep.h [new file with mode: 0644]
include/asm-ppc64/timex.h
include/asm-ppc64/topology.h
include/asm-s390/extmem.h
include/asm-s390/hardirq.h
include/asm-s390/io.h
include/asm-s390/siginfo.h
include/asm-s390/timex.h
include/asm-sh/addrspace.h
include/asm-sh/bitops.h
include/asm-sh/cpu-sh3/cache.h
include/asm-sh/cpu-sh4/freq.h
include/asm-sh/edosk7705/io.h [new file with mode: 0644]
include/asm-sh/freq.h
include/asm-sh/hardirq.h
include/asm-sh/io.h
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/mmu_context.h
include/asm-sh/rtc.h
include/asm-sh/se/se.h
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-sh/shmparam.h
include/asm-sh/system.h
include/asm-sh/thread_info.h
include/asm-sh/timex.h
include/asm-sh/user.h
include/asm-sh/watchdog.h
include/asm-sh64/io.h
include/asm-sh64/pgtable.h
include/asm-sparc/elf.h
include/asm-sparc/errno.h
include/asm-sparc/fbio.h
include/asm-sparc/io.h
include/asm-sparc/mostek.h
include/asm-sparc/sigcontext.h
include/asm-sparc/timex.h
include/asm-sparc64/errno.h
include/asm-sparc64/kprobes.h
include/asm-sparc64/timex.h
include/asm-um/atomic.h
include/asm-um/hardirq.h
include/asm-um/ptrace-generic.h
include/asm-v850/hardirq.h
include/asm-v850/io.h
include/asm-v850/posix_types.h
include/asm-v850/timex.h
include/asm-x86_64/apic.h
include/asm-x86_64/cpufeature.h
include/asm-x86_64/desc.h
include/asm-x86_64/elf.h
include/asm-x86_64/genapic.h [new file with mode: 0644]
include/asm-x86_64/hardirq.h
include/asm-x86_64/hpet.h
include/asm-x86_64/io_apic.h
include/asm-x86_64/ipi.h [new file with mode: 0644]
include/asm-x86_64/kdebug.h
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/nmi.h
include/asm-x86_64/numa.h
include/asm-x86_64/proto.h
include/asm-x86_64/swiotlb.h
include/asm-x86_64/system.h
include/asm-x86_64/thread_info.h
include/asm-x86_64/vsyscall.h
include/linux/atmsvc.h
include/linux/bitops.h
include/linux/byteorder/big_endian.h
include/linux/byteorder/little_endian.h
include/linux/cyclomx.h
include/linux/cycx_drv.h
include/linux/device-mapper.h
include/linux/dio.h
include/linux/divert.h
include/linux/dm-ioctl.h
include/linux/dnotify.h
include/linux/dvb/frontend.h
include/linux/eeprom.h
include/linux/efs_fs.h
include/linux/gen_stats.h
include/linux/generic_serial.h
include/linux/genhd.h
include/linux/hardirq.h
include/linux/hdreg.h
include/linux/hpet.h
include/linux/i2c-sensor.h
include/linux/i2c-vid.h
include/linux/icmp.h
include/linux/if_ppp.h
include/linux/if_vlan.h
include/linux/inet.h
include/linux/input.h
include/linux/ioport.h
include/linux/ipv6_route.h
include/linux/irq.h
include/linux/jiffies.h
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
include/linux/list.h
include/linux/mc146818rtc.h
include/linux/mempolicy.h
include/linux/meye.h
include/linux/mmc/mmc.h
include/linux/msdos_fs_i.h
include/linux/msdos_fs_sb.h
include/linux/netfilter_ipv4/ip_conntrack_tcp.h
include/linux/netfilter_ipv4/ip_nat_protocol.h
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_connmark.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_hashlimit.h [new file with mode: 0644]
include/linux/nfs4.h
include/linux/nodemask.h [new file with mode: 0644]
include/linux/parport_pc.h
include/linux/pci-acpi.h [new file with mode: 0644]
include/linux/pktcdvd.h [new file with mode: 0644]
include/linux/pnp.h
include/linux/profile.h
include/linux/raid/md.h
include/linux/raid/md_k.h
include/linux/raid/md_p.h
include/linux/raid/multipath.h
include/linux/raid/raid1.h
include/linux/rbtree.h
include/linux/rslib.h [new file with mode: 0644]
include/linux/scatterlist.h [new file with mode: 0644]
include/linux/sctp.h
include/linux/serial.h
include/linux/serial_8250.h [new file with mode: 0644]
include/linux/serial_reg.h
include/linux/smb_fs.h
include/linux/smb_mount.h
include/linux/sonypi.h
include/linux/swapops.h
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/threads.h
include/linux/ticable.h
include/linux/topology.h
include/linux/usb_sl811.h [new file with mode: 0644]
include/linux/via.h [new file with mode: 0644]
include/linux/wireless.h
include/media/audiochip.h
include/media/saa6752hs.h
include/media/saa7146.h
include/media/tuner.h
include/media/video-buf-dvb.h [new file with mode: 0644]
include/mtd/mtd-abi.h
include/net/act_api.h [new file with mode: 0644]
include/net/dn_nsp.h
include/net/gen_stats.h
include/net/ip_vs.h
include/net/irda/ircomm_tty_attach.h
include/net/irda/irias_object.h
include/net/irda/timer.h
include/net/iw_handler.h
include/net/ndisc.h
include/net/pkt_act.h
include/net/sch_generic.h [new file with mode: 0644]
include/net/sctp/structs.h
include/net/sctp/ulpevent.h
include/net/sctp/user.h
include/net/tc_act/tc_gact.h
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/udp.h
include/net/x25device.h [new file with mode: 0644]
include/pcmcia/bulkmem.h
include/pcmcia/cistpl.h
include/pcmcia/cs.h
include/sound/hdsp.h
include/sound/opl3.h
include/sound/pcm.h
include/sound/seq_kernel.h
include/video/kyro.h
include/video/mach64.h
include/video/tdfx.h
include/video/tgafb.h
init/do_mounts.c
init/do_mounts_devfs.c
kernel/exec_domain.c
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
kernel/ksysfs.c [new file with mode: 0644]
kernel/power/Kconfig
kernel/power/disk.c
kernel/power/main.c
kernel/profile.c
kernel/resource.c
kernel/stop_machine.c
kernel/sys_ni.c [new file with mode: 0644]
kernel/wait.c [new file with mode: 0644]
lib/Kconfig.debug
lib/dec_and_lock.c
lib/inflate.c
lib/iomap.c
lib/kernel_lock.c [new file with mode: 0644]
lib/kobject_uevent.c [new file with mode: 0644]
lib/parser.c
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]
mm/mempolicy.c
mm/thrash.c
mm/tiny-shmem.c
net/802/fddi.c
net/802/hippi.c
net/appletalk/Makefile
net/appletalk/dev.c [new file with mode: 0644]
net/atm/mpc.c
net/bluetooth/cmtp/capi.c
net/bluetooth/rfcomm/tty.c
net/bridge/br_netfilter.c
net/core/dev_mcast.c
net/core/ethtool.c
net/core/gen_estimator.c
net/core/gen_stats.c
net/core/link_watch.c
net/core/wireless.c
net/decnet/Kconfig
net/decnet/dn_neigh.c
net/decnet/dn_nsp_out.c
net/ipv4/fib_rules.c
net/ipv4/ipvs/ip_vs_conn.c
net/ipv4/ipvs/ip_vs_ftp.c
net/ipv4/ipvs/ip_vs_lblc.c
net/ipv4/ipvs/ip_vs_lblcr.c
net/ipv4/netfilter/ip_conntrack_irc.c
net/ipv4/netfilter/ip_conntrack_tftp.c
net/ipv4/netfilter/ip_nat_ftp.c
net/ipv4/netfilter/ip_nat_irc.c
net/ipv4/netfilter/ip_nat_proto_icmp.c
net/ipv4/netfilter/ip_nat_proto_tcp.c
net/ipv4/netfilter/ip_nat_proto_udp.c
net/ipv4/netfilter/ip_nat_proto_unknown.c
net/ipv4/netfilter/ip_nat_rule.c
net/ipv4/netfilter/ip_nat_tftp.c
net/ipv4/netfilter/ip_queue.c
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_ECN.c
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_recent.c
net/ipv4/netfilter/ipt_tcpmss.c
net/ipv4/netfilter/iptable_filter.c
net/ipv4/tcp_diag.c
net/ipv4/xfrm4_input.c
net/ipv4/xfrm4_output.c
net/ipv6/Kconfig
net/ipv6/ip6_fib.c
net/ipv6/netfilter/ip6_queue.c
net/ipv6/netfilter/ip6t_MARK.c
net/ipv6/netfilter/ip6t_ah.c
net/ipv6/netfilter/ip6t_dst.c
net/ipv6/netfilter/ip6t_esp.c
net/ipv6/netfilter/ip6t_eui64.c
net/ipv6/netfilter/ip6t_frag.c
net/ipv6/netfilter/ip6t_hbh.c
net/ipv6/netfilter/ip6t_hl.c
net/ipv6/netfilter/ip6t_ipv6header.c
net/ipv6/netfilter/ip6t_length.c
net/ipv6/netfilter/ip6t_limit.c
net/ipv6/netfilter/ip6t_mac.c
net/ipv6/netfilter/ip6t_mark.c
net/ipv6/netfilter/ip6t_multiport.c
net/ipv6/netfilter/ip6t_physdev.c
net/ipv6/netfilter/ip6t_rt.c
net/ipv6/xfrm6_output.c
net/irda/ircomm/ircomm_tty_attach.c
net/irda/irias_object.c
net/irda/irlan/irlan_client.c
net/irda/irlan/irlan_common.c
net/irda/irlan/irlan_provider.c
net/irda/irmod.c
net/irda/irnet/irnet_ppp.c
net/irda/qos.c
net/irda/timer.c
net/netlink/netlink_dev.c
net/netrom/nr_route.c
net/sched/act_api.c
net/sched/cls_rsvp.c
net/sched/cls_rsvp6.c
net/sched/gact.c
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/sched/sch_dsmark.c
net/sched/sch_fifo.c
net/sched/sch_netem.c
net/sched/sch_sfq.c
net/sched/sch_teql.c
net/sctp/transport.c
net/x25/x25_dev.c
net/x25/x25_proc.c
net/xfrm/Kconfig
scripts/Makefile.build
scripts/Makefile.clean
scripts/Makefile.lib
scripts/basic/docproc.c
scripts/basic/split-include.c
scripts/checkstack.pl
scripts/conmakehash.c
scripts/gen_initramfs_list.sh [new file with mode: 0644]
scripts/kconfig/confdata.c
scripts/kconfig/symbol.c
scripts/lxdialog/Makefile
scripts/lxdialog/dialog.h
scripts/mksysmap
scripts/mod/file2alias.c
scripts/mod/modpost.c
scripts/mod/modpost.h
scripts/mod/sumversion.c
security/Kconfig
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]
security/security.c
sound/Kconfig
sound/arm/Kconfig
sound/core/info.c
sound/core/memory.c
sound/core/pcm.c
sound/core/seq/seq_device.c
sound/drivers/Kconfig
sound/drivers/mpu401/mpu401_uart.c
sound/oss/ad1889.h
sound/oss/ali5455.c
sound/oss/au1000.c
sound/oss/btaudio.c
sound/oss/cs4281/cs4281m.c
sound/oss/cs46xx.c
sound/oss/es1370.c
sound/oss/es1371.c
sound/oss/esssolo1.c
sound/oss/forte.c
sound/oss/ite8172.c
sound/oss/maestro.c
sound/oss/maestro3.c
sound/oss/msnd_pinnacle.c
sound/oss/nm256.h
sound/oss/rme96xx.c
sound/oss/sonicvibes.c
sound/oss/ymfpci.c
sound/oss/ymfpci.h
sound/parisc/Kconfig
sound/pci/ac97/Makefile
sound/pci/ac97/ac97_id.h
sound/pci/ac97/ac97_patch.h
sound/pci/atiixp_modem.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/emu10k1/emupcm.c
sound/pci/emu10k1/emuproc.c
sound/pci/ice1712/delta.h
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/mixart/mixart.h
sound/ppc/Kconfig
sound/ppc/daca.c
sound/usb/Kconfig
sound/usb/usbmidi.c
sound/usb/usbmixer_maps.c
sound/usb/usx2y/usbusx2y.c
sound/usb/usx2y/usbusx2yaudio.c
usr/Makefile
usr/gen_init_cpio.c

index 008c547..a8c19aa 100644 (file)
@@ -20,6 +20,8 @@ Changes
        - list of changes that break older software packages.
 CodingStyle
        - how the boss likes the C code in the kernel to look.
+DMA-API.txt
+       - DMA API, pci_ API & extensions for non-consistent memory machines.
 DMA-mapping.txt
        - info for PCI drivers using DMA portably across all platforms.
 DocBook/
@@ -30,8 +32,12 @@ IPMI.txt
        - info on Linux Intelligent Platform Management Interface (IPMI) Driver.
 IRQ-affinity.txt
        - how to select which CPU(s) handle which interrupt events on SMP.
+ManagementStyle
+       - how to (attempt to) manage kernel hackers.
 MSI-HOWTO.txt
        - the Message Signaled Interrupts (MSI) Driver Guide HOWTO and FAQ.
+RCU/
+       - directory with info on RCU (read-copy update).
 README.DAC960
        - info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux.
 README.moxa
@@ -46,8 +52,6 @@ VGA-softcursor.txt
        - how to change your VGA cursor from a blinking underscore.
 arm/
        - directory with info about Linux on the ARM architecture.
-as-iosched.txt
-       - info on anticipatory IO scheduler.
 basic_profiling.txt
        - basic instructions for those who wants to profile Linux kernel.
 binfmt_misc.txt
@@ -60,20 +64,24 @@ cciss.txt
        - info, major/minor #'s for Compaq's SMART Array Controllers.
 cdrom/
        - directory with information on the CD-ROM drivers that Linux has.
+cli-sti-removal.txt
+       - cli()/sti() removal guide.
 computone.txt
        - info on Computone Intelliport II/Plus Multiport Serial Driver.
 cpqarray.txt
        - info on using Compaq's SMART2 Intelligent Disk Array Controllers.
-cpufreq/
+cpu-freq/
        - info on CPU frequency and voltage scaling.
 cris/
        - directory with info about Linux on CRIS architecture.
+crypto/
+       - directory with info on the Crypto API.
 debugging-modules.txt
        - some notes on debugging modules after Linux 2.6.3.
+device-mapper/
+       - directory with info on Device Mapper.
 devices.txt
        - plain ASCII listing of all the nodes in /dev/ with major minor #'s.
-digiboard.txt
-       - info on the Digiboard PC/X{i,e,eve} multiport boards.
 digiepca.txt
        - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
 dnotify.txt
@@ -92,6 +100,8 @@ fb/
        - directory with info on the frame buffer graphics abstraction layer.
 filesystems/
        - directory with info on the various filesystems that Linux supports.
+firmware_class/
+       - request_firmware() hotplug interface info.
 floppy.txt
        - notes and driver options for the floppy disk driver.
 ftape.txt
@@ -100,10 +110,14 @@ hayes-esp.txt
        - info on using the Hayes ESP serial driver.
 highuid.txt
        - notes on the change from 16 bit to 32 bit user/group IDs.
+hpet.txt
+       - High Precision Event Timer Driver for Linux.
 hw_random.txt
        - info on Linux support for random number generator in i8xx chipsets.
 i2c/
        - directory with info about the I2C bus/protocol (2 wire, kHz speed).
+i2o/
+       - directory with info about the Linux I2O subsystem.
 i386/
        - directory with info about Linux on Intel 32 bit architecture.
 ia64/
@@ -114,6 +128,8 @@ initrd.txt
        - how to use the RAM disk as an initial/temporary root filesystem.
 input/
        - info on Linux input device support.
+io_ordering.txt
+       - info on ordering I/O writes to memory-mapped addresses.
 ioctl-number.txt
        - how to implement and register device/driver ioctl calls.
 iostats.txt
@@ -134,6 +150,8 @@ kernel-parameters.txt
        - summary listing of command line / boot prompt args for the kernel.
 kobject.txt
        - info of the kobject infrastructure of the Linux kernel.
+laptop-mode.txt
+       - How to conserve battery power using laptop-mode.
 ldm.txt
        - a brief description of LDM (Windows Dynamic Disks).
 locks.txt
@@ -158,8 +176,8 @@ mips/
        - directory with info about Linux on MIPS architecture.
 mkdev.cciss
        - script to make /dev entries for SMART controllers (see cciss.txt).
-mkdev.ida
-       - script to make /dev entries for Intelligent Disk Array Controllers.
+mono.txt
+       - how to execute Mono-based .NET binaries with the help of BINFMT_MISC.
 moxa-smartio
        - info on installing/using Moxa multiport serial driver.
 mtrr.txt
@@ -172,6 +190,8 @@ nfsroot.txt
        - short guide on setting up a diskless box with NFS root filesystem.
 nmi_watchdog.txt
        - info on NMI watchdog for SMP systems.
+numastat.txt
+       - info on how to read Numa policy hit/miss statistics in sysfs.
 oops-tracing.txt
        - how to decode those nasty internal kernel error dump messages.
 paride.txt
@@ -199,17 +219,25 @@ ramdisk.txt
 riscom8.txt
        - notes on using the RISCom/8 multi-port serial driver.
 rocket.txt
-       - info on installing/using the Comtrol RocketPort multiport serial driver.
+       - info on the Comtrol RocketPort multiport serial driver.
 rpc-cache.txt
        - introduction to the caching mechanisms in the sunrpc layer.
 rtc.txt
        - notes on how to use the Real Time Clock (aka CMOS clock) driver.
 s390/
        - directory with info on using Linux on the IBM S390.
+sched-coding.txt
+       - reference for various scheduler-related methods in the O(1) scheduler.
 sched-design.txt
        - goals, design and implementation of the Linux O(1) scheduler.
+sched-domains.txt
+       - information on scheduling domains.
+sched-stats.txt
+       - information on schedstats (Linux Scheduler Statistics).
 scsi/
        - directory with info on Linux scsi support.
+serial/
+       - directory with info on the low level serial API.
 serial-console.txt
        - how to set up Linux with a serial line console as the default.
 sgi-visws.txt
@@ -242,14 +270,24 @@ sysrq.txt
        - info on the magic SysRq key.
 telephony/
        - directory with info on telephony (e.g. voice over IP) support.
+time_interpolators.txt
+       - info on time interpolators.
+tipar.txt
+       - information about Parallel link cable for Texas Instruments handhelds.
+tty.txt
+       - guide to the locking policies of the tty layer.
 unicode.txt
        - info on the Unicode character/font mapping used in Linux.
+uml/
+       - directory with infomation about User Mode Linux.
 usb/
        - directory with info regarding the Universal Serial Bus.
 video4linux/
        - directory with info regarding video/TV/radio cards and linux.
 vm/
        - directory with info on the Linux vm code.
+voyager.txt
+       - guide to running Linux on the Voyager architecture.
 watchdog/
        - how to auto-reboot Linux if it has "fallen and can't get up". ;-)
 x86_64/
index 9a23eab..fc50b10 100644 (file)
@@ -8,10 +8,10 @@
 
 DOCBOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
            kernel-hacking.sgml kernel-locking.sgml via-audio.sgml \
-           mousedrivers.sgml deviceiobook.sgml procfs-guide.sgml \
-           tulip-user.sgml writing_usb_driver.sgml scsidrivers.sgml \
-           sis900.sgml kernel-api.sgml journal-api.sgml lsm.sgml usb.sgml \
-           gadget.sgml libata.sgml
+           deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
+           writing_usb_driver.sgml scsidrivers.sgml sis900.sgml \
+           kernel-api.sgml journal-api.sgml lsm.sgml usb.sgml \
+           gadget.sgml libata.sgml mtdnand.sgml librs.sgml
 
 ###
 # The build process is as follows (targets):
@@ -58,14 +58,14 @@ MAKEMAN   = $(PERL) $(srctree)/scripts/makeman
 # The following rules are used to generate the .sgml documentation
 # required to generate the final targets. (ps, pdf, html).
 quiet_cmd_docproc = DOCPROC $@
-      cmd_docproc = $(DOCPROC) doc $< >$@
+      cmd_docproc = SRCTREE=$(srctree)/ $(DOCPROC) doc $< >$@
 define rule_docproc
        set -e;                                                         \
         $(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))';)        \
         $(cmd_$(1));                                                   \
         (                                                              \
           echo 'cmd_$@ := $(cmd_$(1))';                                \
-          echo $@: `$(DOCPROC) depend $<`;                             \
+          echo $@: `SRCTREE=$(srctree) $(DOCPROC) depend $<`;          \
         ) > $(dir $@).$(notdir $@).cmd
 endef
 
@@ -129,6 +129,9 @@ quiet_cmd_db2html = DB2HTML $@
 # Rule to generate man files - output is placed in the man subdirectory
 
 %.9:   %.sgml
+ifneq ($(KBUILD_SRC),)
+       $(Q)mkdir -p $(objtree)/Documentation/DocBook/man
+endif
        $(SPLITMAN) $< $(objtree)/Documentation/DocBook/man "$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)"
        $(MAKEMAN) convert $(objtree)/Documentation/DocBook/man $<
 
index d3f4183..0d1da8c 100644 (file)
        compiler is not permitted to reorder the I/O sequence. When the 
        ordering can be compiler optimised, you can use <function>
        __readb</function> and friends to indicate the relaxed ordering. Use 
-       this with care. The <function>rmb</function> provides a read memory 
-       barrier. The <function>wmb</function> provides a write memory barrier.
+       this with care.
       </para>
 
       <para>
        asynchronously. A driver author must issue a read from the same
        device to ensure that writes have occurred in the specific cases the
        author cares. This kind of property cannot be hidden from driver
-       writers in the API.
+       writers in the API.  In some cases, the read used to flush the device
+       may be expected to fail (if the card is resetting, for example).  In
+       that case, the read should be done from config space, which is
+       guaranteed to soft-fail if the card doesn't respond.
+      </para>
+
+      <para>
+       The following is an example of flushing a write to a device when
+       the driver would like to ensure the write's effects are visible prior
+       to continuing execution.
+      </para>
+
+<programlisting>
+static inline void
+qla1280_disable_intrs(struct scsi_qla_host *ha)
+{
+       struct device_reg *reg;
+
+       reg = ha->iobase;
+       /* disable risc and host interrupts */
+       WRT_REG_WORD(&amp;reg->ictrl, 0);
+       /*
+        * The following read will ensure that the above write
+        * has been received by the device before we return from this
+        * function.
+        */
+       RD_REG_WORD(&amp;reg->ictrl);
+       ha->flags.ints_enabled = 0;
+}
+</programlisting>
+
+      <para>
+       In addition to write posting, on some large multiprocessing systems
+       (e.g. SGI Challenge, Origin and Altix machines) posted writes won't
+       be strongly ordered coming from different CPUs.  Thus it's important
+       to properly protect parts of your driver that do memory-mapped writes
+       with locks and use the <function>mmiowb</function> to make sure they
+       arrive in the order intended.  Issuing a regular <function>readX
+       </function> will also ensure write ordering, but should only be used
+       when the driver has to be sure that the write has actually arrived
+       at the device (not that it's simply ordered with respect to other
+       writes), since a full <function>readX</function> is a relatively
+       expensive operation.
+      </para>
+
+      <para>
+       Generally, one should use <function>mmiowb</function> prior to
+       releasing a spinlock that protects regions using <function>writeb
+       </function> or similar functions that aren't surrounded by <function>
+       readb</function> calls, which will ensure ordering and flushing.  The
+       following pseudocode illustrates what might occur if write ordering
+       isn't guaranteed via <function>mmiowb</function> or one of the
+       <function>readX</function> functions.
+      </para>
+
+<programlisting>
+CPU A:  spin_lock_irqsave(&amp;dev_lock, flags)
+CPU A:  ...
+CPU A:  writel(newval, ring_ptr);
+CPU A:  spin_unlock_irqrestore(&amp;dev_lock, flags)
+        ...
+CPU B:  spin_lock_irqsave(&amp;dev_lock, flags)
+CPU B:  writel(newval2, ring_ptr);
+CPU B:  ...
+CPU B:  spin_unlock_irqrestore(&amp;dev_lock, flags)
+</programlisting>
+
+      <para>
+       In the case above, newval2 could be written to ring_ptr before
+       newval.  Fixing it is easy though:
+      </para>
+
+<programlisting>
+CPU A:  spin_lock_irqsave(&amp;dev_lock, flags)
+CPU A:  ...
+CPU A:  writel(newval, ring_ptr);
+CPU A:  mmiowb(); /* ensure no other writes beat us to the device */
+CPU A:  spin_unlock_irqrestore(&amp;dev_lock, flags)
+        ...
+CPU B:  spin_lock_irqsave(&amp;dev_lock, flags)
+CPU B:  writel(newval2, ring_ptr);
+CPU B:  ...
+CPU B:  mmiowb();
+CPU B:  spin_unlock_irqrestore(&amp;dev_lock, flags)
+</programlisting>
+
+      <para>
+       See tg3.c for a real world example of how to use <function>mmiowb
+       </function>
       </para>
 
       <para>
        PCI ordering rules also guarantee that PIO read responses arrive
-       after any outstanding DMA writes on that bus, since for some devices
+       after any outstanding DMA writes from that bus, since for some devices
        the result of a <function>readb</function> call may signal to the
        driver that a DMA transaction is complete.  In many cases, however,
        the driver may want to indicate that the next
        <function>readb</function> call has no relation to any previous DMA
        writes performed by the device.  The driver can use
        <function>readb_relaxed</function> for these cases, although only
-       some platforms will honor the relaxed semantics.
+       some platforms will honor the relaxed semantics.  Using the relaxed
+       read functions will provide significant performance benefits on
+       platforms that support it.  The qla2xxx driver provides examples
+       of how to use <function>readX_relaxed</function>.  In many cases,
+       a majority of the driver's <function>readX</function> calls can
+       safely be converted to <function>readX_relaxed</function> calls, since
+       only a few will indicate or depend on DMA completion.
       </para>
     </sect1>
 
index 5f11984..ef66fdd 100644 (file)
@@ -133,6 +133,11 @@ KAO -->
      <sect1><title>Socket Filter</title>
 !Enet/core/filter.c
      </sect1>
+     <sect1><title>Generic Network Statistics</title>
+!Iinclude/linux/gen_stats.h
+!Enet/core/gen_stats.c
+!Enet/core/gen_estimator.c
+     </sect1>
   </chapter>
 
   <chapter id="netdev">
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>
index 669b046..3420623 100644 (file)
     <para>
       I'd like to thank Jeff Garzik
       <email>jgarzik@pobox.com</email> and Alexander Viro
-      <email>viro@math.psu.edu</email> for their input, Tim Waugh
-      <email>twaugh@redhat.com</email> for his <ulink
+      <email>viro@parcelfarce.linux.theplanet.co.uk</email> for their input,
+      Tim Waugh <email>twaugh@redhat.com</email> for his <ulink
       url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>,
       and Marc Joosen <email>marcj@historia.et.tudelft.nl</email> for
       proofreading.
index ddc8173..86edb61 100644 (file)
@@ -119,9 +119,10 @@ you can't use it from the bus master.
 So why do we care about the physical address at all? We do need the physical
 address in some cases, it's just not very often in normal code.  The physical
 address is needed if you use memory mappings, for example, because the
-"remap_page_range()" mm function wants the physical address of the memory to
-be remapped (the memory management layer doesn't know about devices outside
-the CPU, so it shouldn't need to know about "bus addresses" etc). 
+"remap_pfn_range()" mm function wants the physical address of the memory to
+be remapped as measured in units of pages, a.k.a. the pfn (the memory
+management layer doesn't know about devices outside the CPU, so it
+shouldn't need to know about "bus addresses" etc).
 
 NOTE NOTE NOTE! The above is only one part of the whole equation. The above
 only talks about "real memory", that is, CPU memory (RAM). 
index 46950af..bda6ead 100644 (file)
@@ -82,7 +82,7 @@ lock might be used as follows for deletion and insertion:
                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);
+                               write_unlock(&auditsc_lock);
                                return 0;
                        }
                }
index a851d03..fad566b 100644 (file)
@@ -118,6 +118,10 @@ to store page tables.  The recommended placement is 32KiB into RAM.
 
 In either case, the following conditions must be met:
 
+- Quiesce all DMA capable devicess so that memory does not get
+  corrupted by bogus network packets or disk data. This will save
+  you many hours of debug.
+
 - CPU register settings
   r0 = 0,
   r1 = machine type number discovered in (3) above.
index 48ba502..969f165 100644 (file)
@@ -18,7 +18,7 @@ http://developer.intel.com/design/network/products/npfamily/ixp2xxx.htm
 
 2. Linux Support
 
-Linux currently supports the following features on the IXP2000 NPUS:
+Linux currently supports the following features on the IXP2000 NPUs:
 
 - On-chip serial
 - PCI
@@ -30,10 +30,10 @@ 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
+be of help:  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.
+MAILING LISTS REGARDING THE INTEL SDK.
 
 3. Supported Platforms
 
@@ -47,12 +47,12 @@ MAILINNG LISTS REGARDING THE INTEL SDK.
 
 - 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
+  Intel SDK is designed, devices are enumerated in a very 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
+  via HW registers. The "ixdp2x01_clk=XXX" cmd line options allow you
   to pass the clock rate to the board port.
 
 5. Thanks
index d86d818..2e1590b 100644 (file)
@@ -122,6 +122,15 @@ http://developer.intel.com/design/network/products/npfamily/ixdp425.htm
    also known as the Richfield board. It contains 4 PCI slots, 16MB
    of flash, two 10/100 ports and one ADSL port.
 
+Intel IXDPG425 Development Platform
+
+   This is basically and ADI Coyote board with a NEC EHCI controller
+   added. One issue with this board is that the mini-PCI slots only
+   have the 3.3v line connected, so you can't use a PCI to mini-PCI
+   adapter with an E100 card. So to NFS root you need to use either
+   the CSR or a WiFi card and a ramdisk that BOOTPs and then does
+   a pivot_root to NFS.
+
 Motorola PrPMC1100 Processor Mezanine Card
 http://www.fountainsys.com/datasheet/PrPMC1100.pdf
 
@@ -152,4 +161,4 @@ Robert E. Ranslam
 
 -------------------------------------------------------------------------
 
-Last Update: 5/13/2004
+Last Update: 11/16/2004
index 1dd5d6c..a6f718e 100644 (file)
@@ -163,9 +163,9 @@ CONFIG_MACH_ and CONFIG_ARCH_
 
     <http://www.arm.linux.org.uk/developer/machines/>
 
-Kernel entry (head-armv.S)
+Kernel entry (head.S)
 --------------------------
-  The initial entry into the kernel is via head-armv.S, which uses machine
+  The initial entry into the kernel is via head.S, which uses machine
   independent code.  The machine is selected by the value of 'r1' on
   entry, which must be kept unique.
 
index 831b98c..000e3d7 100644 (file)
@@ -15,7 +15,7 @@ Configuration
 -------------
 
   To set the default configuration, use `make bast_defconfig` which
-  supports the commonly used features of this board
+  supports the commonly used features of this board.
 
 
 Support
@@ -23,15 +23,23 @@ 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
+
+  Useful links:
+
+    - Resources Page http://www.simtec.co.uk/products/EB2410ITX/resources.html
+
+    - Board FAQ at http://www.simtec.co.uk/products/EB2410ITX/faq.html
+
+    - Bootloader info http://www.simtec.co.uk/products/SWABLE/resources.html
+      and FAQ http://www.simtec.co.uk/products/SWABLE/faq.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.
+  The NAND and NOR support has been merged from the linux-mtd project.
+  Any prolbems, see http://www.linux-mtd.infradead.org/ for more
+  information or up-to-date versions of linux-mtd.
 
 
 IDE
@@ -41,4 +49,10 @@ IDE
   changing speed of devices, PIO Mode 4 capable drives should be used.
 
 
+Maintainers
+-----------
+
+  This board is maintained by Simtec Electronics.
+
+
 (c) 2004 Ben Dooks, Simtec Electronics
index aa3f83a..b8ba492 100644 (file)
@@ -48,9 +48,9 @@ Machines
 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/
+  The current kernels now have support for the s3c2410 NAND
+  controller. If there are any problems the latest linux-mtd
+  CVS can be found from http://www.linux-mtd.infradead.org/
 
 
 Serial
@@ -84,12 +84,21 @@ Clock Management
 Port Contributors
 -----------------
 
-  Ben Dooks
+  Ben Dooks (BJD)
   Vincent Sanders
   Herbert Potzl
-  Arnaud Patard
+  Arnaud Patard (RTP)
   Roc Wu
+  Klaus Fetscher
+  Dimitry Andric
 
+Document Changes
+----------------
+
+  05 Sep 2004 - BJD - Added Document Changes section
+  05 Sep 2004 - BJD - Added Klaus Fetscher to list of contributors
+  25 Oct 2004 - BJD - Added Dimitry Andric to list of contributors
+  25 Oct 2004 - BJD - Updated the MTD from the 2.6.9 merge
 
 Document Author
 ---------------
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
+
index bf34e04..c0d8853 100644 (file)
@@ -5,7 +5,7 @@ Due to an unfortunate oversight when the Card Engines were designed,
 the signals that control access to some peripherals, most notably the
 SMC91C9111 ethernet controller, are not properly handled.
 
-The symptom is that back to back IO with the peripheral returns
+The symptom is that some back to back IO with the peripheral returns
 unreliable data.  With the SMC chip, you'll see errors about the bank
 register being 'screwed'.
 
@@ -13,20 +13,33 @@ The cause is that the AEN signal to the SMC chip does not transition
 for every memory access.  It is driven through the CPLD from the CS7
 line of the CPU's static memory controller which is optimized to
 eliminate unnecessary transitions.  Yet, the SMC requires a transition
-for every access.  The Sharp website has more information on the
-effect of this power conservation feature on peripheral interfacing.
+for every write access.  The Sharp website has more information about
+the effect this power-conserving feature has on peripheral
+interfacing.
 
-The solution is to follow every access to the SMC chip with an access
-to another memory region that will force the CPU to release the chip
-select line.  Note that it is important to guarantee that the access
-will force the CPU off-chip.  We map a page of SDRAM as if it were an
-uncacheable IO device and read from it after every SMC IO operation.
+The solution is to follow every write access to the SMC chip with an
+access to another memory region that will force the CPU to release the
+chip select line.  It is important to guarantee that this access
+forces the CPU off-chip.  We map a page of SDRAM as if it were an
+uncacheable IO device and read from it after every SMC IO write
+operation.
 
   SMC IO
   BARRIER IO
 
-You might be tempted to believe that we must access another device
+Only this sequence is important.  It does not matter that there is no
+BARRIER IO before the access to the SMC chip because the AEN latch
+only needs occurs after the SMC IO write cycle.  The routines that
+implement this work-around make an additional concession which is to
+disable interrupts during the IO sequence.  Other hardware devices
+(the LogicPD CPLD) have registers in the same the physical memory
+region as the SMC chip.  An interrupt might allow an access to one of
+those registers while SMC IO is being performed.
+
+You might be tempted to think that we have to access another device
 attached to the static memory controller, but the empirical evidence
 indicates that this is not so.  Mapping 0x00000000 (flash) and
 0xc0000000 (SDRAM) appear to have the same effect.  Using SDRAM seems
-to be faster.
+to be faster.  Choosing to access an undecoded memory region is not
+desirable as there is no way to know how that chip select will be used
+in the future.
index fd763cc..6f47332 100644 (file)
@@ -132,7 +132,7 @@ a combination of IO behavior from all those devices.
 Tuning the anticipatory IO scheduler
 ------------------------------------
 When using 'as', the anticipatory IO scheduler there are 5 parameters under
-/sys/block/*/iosched/. All are units of milliseconds.
+/sys/block/*/queue/iosched/. All are units of milliseconds.
 
 The parameters are:
 * read_expire
index f24dbca..6dd274d 100644 (file)
@@ -1172,8 +1172,7 @@ PIO drivers (or drivers that need to revert to PIO transfer once in a
 while (IDE for example)), where the CPU is doing the actual data
 transfer a virtual mapping is needed. If the driver supports highmem I/O,
 (Sec 1.1, (ii) ) it needs to use __bio_kmap_atomic and bio_kmap_irq to
-temporarily map a bio into the virtual address space. See how IDE handles
-this with ide_map_buffer.
+temporarily map a bio into the virtual address space.
 
 
 8. Prior/Related/Impacted patches
index 2b13186..c918b3a 100644 (file)
@@ -9,7 +9,7 @@ Each io queue has a set of io scheduler tunables associated with it. These
 tunables control how the io scheduler works. You can find these entries
 in:
 
-/sys/block/<device>/iosched
+/sys/block/<device>/queue/iosched
 
 assuming that you have sysfs mounted on /sys. If you don't have sysfs mounted,
 you can do so by typing:
index eae6896..916dafe 100644 (file)
@@ -22,6 +22,8 @@ mcdx
        - info on improved Mitsumi CD-ROM driver.
 optcd
        - info on the Optics Storage 8000 AT CD-ROM driver
+packet-writing.txt
+       - Info on the CDRW packet writing module
 sbpcd
        - info on the SoundBlaster/Panasonic CD-ROM interface driver.
 sjcd
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.
index ea2b5d3..b1cf59b 100644 (file)
@@ -1,3 +1,13 @@
+NOTE: This is an unmaintained driver.  It is not guaranteed to work due to
+changes made in the tty layer in 2.6.  If you wish to take over maintenance of
+this driver, contact Michael Warfield <mhw@wittsend.com>.
+
+Changelog:
+----------
+11-01-2001:    Original Document
+
+10-29-2004:    Minor misspelling & format fix, update status of driver.
+               James Nelson <james4765@gmail.com>
 
 Computone Intelliport II/Plus Multiport Serial Driver
 -----------------------------------------------------
@@ -146,7 +156,7 @@ selects polled mode). If no base addresses are specified the defaults in
 ip2.c are used. If you are autoloading the driver module with kerneld or
 kmod the base addresses and interrupt number must also be set in ip2.c
 and recompile or just insert and options line in /etc/modprobe.conf or both.
-The options line is equivalent to the command line and takes precidence over 
+The options line is equivalent to the command line and takes precedence over
 what is in ip2.c. 
 
 /etc/modprobe.conf sample:
@@ -166,7 +176,8 @@ The equivalent for the kernel command line (in lilo.conf):
 
 
 Note:  Both io and irq should be updated to reflect YOUR system.  An "io"
-       address of 1 or 2 indicates a PCI or EISA card in the board table.              The PCI or EISA irq will be assigned automatically.
+       address of 1 or 2 indicates a PCI or EISA card in the board table.
+       The PCI or EISA irq will be assigned automatically.
 
 Specifying an invalid or in-use irq will default the driver into
 running in polled mode for that card.  If all irq entries are 0 then
index d0e185f..c7154e2 100644 (file)
@@ -26,31 +26,13 @@ unable to test against these cards:
        * IDA-2
        * IAES
 
-Installing:
------------
-
-You need to build a new kernel to use this device, even if you want to
-use a loadable module.  
-
-Apply the patch to a 2.2.x kernel:
-
-# cd linux
-# patch -p1 <smart2.patch
-
-Then build a new kernel and turn on Compaq SMART2 Disk Array support.
-Create device nodes for the diskarray device:
-
-# mkdev.ida [ctlrs]
-
-Where ctlrs is the number of controllers you have (defaults to 1 if not
-specified).
 
 EISA Controllers:
 -----------------
 
 If you want to use an EISA controller you'll have to supply some
-insmod/lilo parameters.  If the driver is compiled into the kernel, must
-give it the controller's IO port address at boot time (it is no longer
+modprobe/lilo parameters.  If the driver is compiled into the kernel, must
+give it the controller's IO port address at boot time (it is not
 necessary to specify the IRQ).  For example, if you had two SMART-2/E
 controllers, in EISA slots 1 and 2 you'd give it a boot argument like
 this:
@@ -59,29 +41,27 @@ this:
 
 If you were loading the driver as a module, you'd give load it like this:
 
-       insmod cpqarray.o eisa=0x1000,0x2000
+       modprobe cpqarray eisa=0x1000,0x2000
 
 You can use EISA and PCI adapters at the same time.
 
-Booting:
---------
-
-You'll need to use a modified lilo if you want to boot from a disk array.
-Its simply a version of lilo with some code added to tell it how to
-understand Compaq diskarray devices.
 
 Device Naming:
 --------------
 
-You need some entries in /dev for the ida device.  The mkdev.ida script
-can make device nodes for you automatically.  Currently the device setup
-is as follows:
+You need some entries in /dev for the ida device.  MAKEDEV in the /dev
+directory can make device nodes for you automatically.  The device setup is
+as follows:
 
 Major numbers:
        72      ida0
        73      ida1
        74      ida2
-       etc...
+       75      ida3
+       76      ida4
+       77      ida5
+       78      ida6
+       79      ida7
 
 Minor numbers:
         b7 b6 b5 b4 b3 b2 b1 b0
@@ -91,7 +71,7 @@ Minor numbers:
              |
              +-------------------- Logical Volume number
 
-The suggested device naming scheme is:
+The device naming scheme is:
 /dev/ida/c0d0          Controller 0, disk 0, whole device
 /dev/ida/c0d0p1                Controller 0, disk 0, partition 1
 /dev/ida/c0d0p2                Controller 0, disk 0, partition 2
@@ -101,3 +81,13 @@ The suggested device naming scheme is:
 /dev/ida/c1d1p1                Controller 1, disk 1, partition 1
 /dev/ida/c1d1p2                Controller 1, disk 1, partition 2
 /dev/ida/c1d1p3                Controller 1, disk 1, partition 3
+
+
+Changelog:
+==========
+
+10-28-2004 :   General cleanup, syntax fixes for in-kernel driver version.
+               James Nelson <james4765@gmail.com>
+
+
+1999 :         Original Document
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.
+
+
index 5e6391c..7fedc00 100644 (file)
@@ -65,6 +65,7 @@ Intel Pentium 4, Intel Xeon
 Intel Pentium M (Centrino)
 National Semiconductors Geode GX
 Transmeta Crusoe
+Transmeta Efficeon
 VIA Cyrix 3 / C3
 various processors on some ACPI 2.0-compatible systems [*]
 
index 62778c5..fa0c8b9 100644 (file)
@@ -231,6 +231,9 @@ Whirlpool algorithm contributors:
   Aaron Grothe
   Jean-Luc Cooke
 
+Anubis algorithm contributors:
+  Aaron Grothe
+
 Generic scatterwalk code by Adam J. Richter <adam@yggdrasil.com>
 
 Please send any credits updates or corrections to:
index 01c4adc..88820fe 100644 (file)
@@ -1,3 +1,11 @@
+NOTE:  This driver is obsolete.  Digi provides a 2.6 driver (dgdm) at
+http://www.digi.com for PCI cards.  They no longer maintain this driver,
+and have no 2.6 driver for ISA cards.
+
+This driver requires a number of user-space tools.  They can be aquired from
+http://www.digi.com, but only works with 2.4 kernels.
+
+
 The Digi Intl. epca driver. 
 ----------------------------
 The Digi Intl. epca driver for Linux supports the following boards:
@@ -64,9 +72,6 @@ drivers/char/README.epca for more details.  Note,
 this driver REQUIRES that digiDload be executed prior to it being used. 
 Failure to do this will result in an ENODEV error.
 
-The latest version of the tool package is available at:
-ftp://ftp.dgii.com/drivers/linux/released/async/
-
 Documentation:
 --------------
 Complete documentation for this product may be found in the tool package. 
@@ -74,14 +79,8 @@ Complete documentation for this product may be found in the tool package.
 Sources of information and support:
 -----------------------------------
 Digi Intl. support site for this product:
--> digilnux@dgii.com 
 
-Related information and information concerning other drivers supporting 
-Digi Intl. products:
-
--> FTP: ftp://dgii.com
--> Webpage: http://www.dgii.com
--> Webpage: http://lameter.com/digi
+->  http://www.digi.com
 
 Acknowledgments:
 ----------------
@@ -90,3 +89,10 @@ supporting the original public domain DigiBoard driver Copyright (C)
 1994,1995 Troy De Jongh.  Many thanks to Christoph Lameter 
 (christoph@lameter.com) and Mike McLagan (mike.mclagan@linux.org) who authored 
 and contributed to the original document. 
+
+Changelog:
+----------
+10-29-04:      Update status of driver, remove dead links in document
+               James Nelson <james4765@gmail.com>
+
+2000 (?)       Original Document
index 3434cb3..6984fca 100644 (file)
@@ -54,6 +54,12 @@ directory "b".
 Also, files that are unlinked, will still cause notifications in the
 last directory that they were linked to.
 
+Configuration
+-------------
+
+Dnotify is controlled via the CONFIG_DNOTIFY configuration option.  When
+disabled, fcntl(fd, F_NOTIFY, ...) will return -EINVAL.
+
 Example
 -------
 
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
index 5d8dbda..09020eb 100644 (file)
@@ -6,7 +6,6 @@ HOWTO: Get An Avermedia DVB-T working under Linux
    Assumptions and Introduction
    The Avermedia DVB-T
    Getting the card going
-   Getting the Firmware
    Receiving DVB-T in Australia
    Known Limitations
    Further Update
@@ -149,28 +148,9 @@ Getting the card going
    to start accessing the card with utilities such as scan, tzap,
    dvbstream etc.
 
-   The  current version of the frontend module sp887x.o, contains
-   no firmware drivers?, so the first time you open it with a DVB
-   utility  the driver will try to download some initial firmware
-   to  the card. You will need to download this firmware from the
-   web,  or  copy  it from an installation of the Windows drivers
-   that probably came with your card, before you can use it.
-
-   The  default  Linux  filesystem  location for this firmware is
-   /usr/lib/hotplug/firmware/sc_main.mc .
-     _________________________________________________________
-
-Getting the Firmware
-
-   As the firmware for the card is no longer contained within the
-   driver,  it  is  necessary  to  extract  it  from  the windows
-   drivers.
-
-   The  Windows  drivers  for the Avermedia DVB-T can be obtained
-   from: http://babyurl.com/H3U970 and you can get an application
-   to extract the firmware from:
-   http://www.kyz.uklinux.net/cabextract.php.
-     _________________________________________________________
+   The frontend module sp887x.o, requires an external   firmware.
+   Please use  the  command "get_dvb_firmware sp887x" to download
+   it. Then copy it to /usr/lib/hotplug/firmware.
 
 Receiving DVB-T in Australia
 
index 695f174..efdc4ee 100644 (file)
@@ -38,6 +38,7 @@ o Frontends drivers:
                                  Comtech DVBT-6k07 (SP5730 PLL)
                                  (NxtWave Communications NXT6000 demodulator)
    - sp887x            : Microtune 7202D
+   - dib3000mb : DiBcom 3000-MB demodulator
   DVB-S/C/T:
    - dst               : TwinHan DST Frontend
 
@@ -49,7 +50,7 @@ o Cards based on the Phillips saa7146 multimedia PCI bridge chip:
   - "budget" cards (i.e. without hardware MPEG decoder):
     - Technotrend Budget / Hauppauge WinTV-Nova PCI Cards
     - SATELCO Multimedia PCI
-    - KNC1 DVB-S
+    - KNC1 DVB-S, Typhoon DVB-S, Terratec Cinergy 1200 DVB-S (no CI support)
     - Typhoon DVB-S budget
     - Fujitsu-Siemens Activy DVB-S budget card
 
@@ -66,4 +67,19 @@ o Technotrend / Hauppauge DVB USB devices:
   - Nova USB
   - DEC 2000-T, 3000-S, 2540-T
 
+o DiBcom DVB-T USB based devices:
+  - Twinhan VisionPlus VisionDTV USB-Ter DVB-T Device
+  - HAMA DVB-T USB device
+  - CTS Portable (Chinese Television System)
+  - KWorld V-Stream XPERT DTV DVB-T USB
+  - JetWay DTV DVB-T USB
+  - ADSTech Instant TV DVB-T USB
+  - Ultima Electronic/Artec T1 USB TVBOX (AN2135 and AN2235)
+  - Compro Videomate DVB-U2000 - DVB-T USB
+  - Grandtec USB DVB-T
+  - Avermedia AverTV DVBT USB
+  - DiBcom USB DVB-T reference device (non-public)
+  - Yakumo DVB-T mobile USB2.0
+  - DiBcom USB2.0 DVB-T reference device (non-public)
+
 o Experimental support for the analog module of the Siemens DVB-C PCI card
index 12026e9..dd40ad6 100644 (file)
@@ -69,6 +69,8 @@ Andreas 'randy' Weinberger
 Kenneth Aafløy <ke-aa@frisurf.no>
   for adding support for Typhoon DVB-S budget card
 
+Ernst Peinlich <e.peinlich@inode.at>
+  for tuning/DiSEqC support for the DEC 3000-s
 
 (If you think you should be in this list, but you are not, drop a
  line to the DVB mailing list)
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);
+}
index 720aa8c..a60c27d 100644 (file)
@@ -28,9 +28,9 @@ is the who-is-who of DVB development
 "faq.txt"
 contains frequently asked questions and their answers.
 
-"firmware.txt" 
-contains informations for required external firmware
-files and where to get them.
+"get_dvb_firmware"
+script to download and extract firmware for those devices
+that require it.
 
 "ttusb-dec.txt"
 contains detailed informations about the
@@ -41,4 +41,11 @@ contains detailed installation instructions for the
 various bt8xx based "budget" DVB cards
 (Nebula, Pinnacle PCTV, Twinhan DST)
 
+"README.dibusb"
+contains detailed information about adapters
+based on DiBcom reference design.
+
+"udev.txt"
+how to get DVB and udev up and running.
+
 Good luck and have fun!
index 4a547fb..5c1e984 100644 (file)
@@ -6,6 +6,8 @@ Driver Status
 
 Supported:
        DEC2000-t
+       DEC2450-t
+       DEC3000-s
        Linux Kernels 2.4 and 2.6
        Video Streaming
        Audio Streaming
@@ -13,52 +15,30 @@ Supported:
        Channel Zapping
        Hotplug firmware loader under 2.6 kernels
 
-In Progress:
-       DEC2540-t
-       DEC3000-s
-
 To Do:
        Tuner status information
        DVB network interface
        Streaming video PC->DEC
+       Conax support for 2450-t
 
 Getting the Firmware
 --------------------
-The firmware can be found in the software update zip files on this page:
-http://www.hauppauge.de/sw_dec.htm
-
-The firmwares are named as follows:
-DEC2000-t:     STB_PC_T.bin
-DEC2540-t:     STB_PC_X.bin
-DEC3000-s:     STB_PC_S.bin
-
-Note that firmwares since version 2.16 beta2 for the DEC2000-t give the device
-the USB ID of the DEC3000-s.  The driver copes with this.
-
-Instructions follow for retrieving version 2.16 of the firmware:
-
-wget http://hauppauge.lightpath.net/de/dec216.exe
-unzip -j dec216.exe software/OEM/STB/App/Boot/STB_PC_T.bin
-unzip -j dec216.exe software/OEM/STB/App/Boot/STB_PC_X.bin
-unzip -j dec216.exe software/OEM/STB/App/Boot/STB_PC_S.bin
+To download the firmware, use the following commands:
+"get_dvb_firmware dec2000t"
+"get_dvb_firmware dec2540t"
+"get_dvb_firmware dec3000s"
 
 
 Compilation Notes for 2.4 kernels
 ---------------------------------
 For 2.4 kernels the firmware for the DECs is compiled into the driver itself.
-The firmwares are expected to be in the build-2.4 directory at compilation
-time.
 
-mv STB_PC_T.bin build-2.4/dvb-ttusb-dec-2000t.fw
-mv STB_PC_X.bin build-2.4/dvb-ttusb-dec-2540t.fw
-mv STB_PC_S.bin build-2.4/dvb-ttusb-dec-3000s.fw
+Copy the three files downloaded above into the build-2.4 directory.
 
 
 Hotplug Firmware Loading for 2.6 kernels
 ----------------------------------------
 For 2.6 kernels the firmware is loaded at the point that the driver module is
-loaded.  See Documentation/dvb/firmware.txt for more information.
+loaded.  See linux/Documentation/dvb/firmware.txt for more information.
 
-mv STB_PC_T.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-2000t.fw
-mv STB_PC_X.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-2540t.fw
-mv STB_PC_S.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-3000s.fw
+Copy the three files downloaded above into the /usr/lib/hotplug/firmware directory.
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.
index 621e3b3..ad7a677 100644 (file)
@@ -223,6 +223,13 @@ dfp:X    - use settings X for digital flat panel interface. X is number from
           selects who is source of display clocks, whether G400, or panel.
           Default value is now read back from hardware - so you should specify
           this value only if you are also using `init' parameter.
+outputs:XYZ - set mapping between CRTC and outputs. Each letter can have value
+           of 0 (for no CRTC), 1 (CRTC1) or 2 (CRTC2), and first letter corresponds
+          to primary analog output, second letter to the secondary analog output
+          and third letter to the DVI output. Default setting is 100 for
+          cards below G400 or G400 without DFP, 101 for G400 with DFP, and
+          111 for G450 and G550. You can set mapping only on first card,
+          use matroxset for setting up other devices.
 vesa:X   - selects startup videomode. X is number from 0 to 0x1FF, see table
            above for detailed explanation. Default is 640x480x8bpp if driver
           has 8bpp support. Otherwise first available of 640x350x4bpp,
index f1c2cee..570ef5d 100644 (file)
@@ -295,13 +295,19 @@ fl_release_private:       yes     yes
 prototypes:
        int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
        void (*fl_notify)(struct file_lock *);  /* unblock callback */
+       void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
+       void (*fl_release_private)(struct file_lock *);
+       void (*fl_break)(struct file_lock *); /* break_lease callback */
 
 locking rules:
                        BKL     may block
 fl_compare_owner:      yes     no
 fl_notify:             yes     no
+fl_copy_lock:          yes     no
+fl_release_private:    yes     yes
+fl_break:              yes     no
 
-       Currently only NLM provides instances of this class. None of the
+       Currently only NFSD and NLM provide instances of this class. None of the
 them block. If you have out-of-tree instances - please, show up. Locking
 in that area will change.
 --------------------------- buffer_head -----------------------------------
@@ -311,8 +317,8 @@ prototypes:
 locking rules:
        called from interrupts. In other words, extreme care is needed here.
 bh is locked, but that's all warranties we have here. Currently only RAID1,
-highmem and fs/buffer.c are providing these. Block devices call this method
-upon the IO completion.
+highmem, fs/buffer.c, and fs/ntfs/aops.c are providing these. Block devices
+call this method upon the IO completion.
 
 --------------------------- block_device_operations -----------------------
 prototypes:
index 1258314..e5aba52 100644 (file)
@@ -1632,7 +1632,7 @@ Changes for patch v177
 - Fixed bugs in handling symlinks: could leak or cause Oops
 
 - Cleaned up directory handling by separating fops
-  Thanks to Alexander Viro <viro@math.psu.edu>
+  Thanks to Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
 ===============================================================================
 Changes for patch v178
 
index 3ef8582..54366ec 100644 (file)
@@ -1349,47 +1349,6 @@ This will cause devfsd to create (and destroy) symbolic links which
 point to the kernel-supplied names.
 
 
-SCSI Host Probing Issues
-
-Devfs allows you to identify SCSI discs based in part on SCSI host
-numbers. If you have only one SCSI host (card) in your computer, then
-clearly it will be given host number 0. Life is not always that easy
-is you have multiple SCSI hosts. Unfortunately, it can sometimes be
-difficult to guess what the probing order of SCSI hosts is. You need
-to know the probe order before you can use device names. To make this
-easy, there is a kernel boot parameter called "scsihosts". This allows
-you to specify the probe order for different types of SCSI hosts. The
-syntax of this parameter is:
-
-scsihosts=<name_1>:<name_2>:<name_3>:...:<name_n>
-
-where <name_1>,<name_2>,...,<name_n> are the names
-of drivers used in the /proc filesystem. For example:
-
-    scsihosts=aha1542:ppa:aha1542::ncr53c7xx
-
-
-means that devices connected to
-
-- first aha1542 controller   - will be /dev/scsi/host0/bus#/target#/lun#
-- first parallel port ZIP    - will be /dev/scsi/host1/bus#/target#/lun#
-- second aha1542 controller  - will be /dev/scsi/host2/bus#/target#/lun#
-- first NCR53C7xx controller - will be /dev/scsi/host4/bus#/target#/lun#
-- any extra controller       - will be /dev/scsi/host5/bus#/target#/lun#,
-                                       /dev/scsi/host6/bus#/target#/lun#, etc
-- if any of above controllers will not be found - the reserved names will
-  not be used by any other device.
-- /dev/scsi/host3/bus#/target#/lun# names will never be used
-
-
-You can use ',' instead of ':' as the separator character if you
-wish. I have used the devfsd naming scheme
-here.
-
-Note that this scheme does not address the SCSI host order if you have
-multiple cards of the same type (such as NCR53c8xx). In this case you
-need to use the driver-specific boot parameters to control this.
-
 -----------------------------------------------------------------------------
 
 
@@ -1952,12 +1911,6 @@ explores the SCSI subsystem and how it interacts with devfs
 
 Douglas Gilbert has written another useful document at
 
-http://www.torque.net/scsi/scsihosts.html which
-discusses the scsihosts= boot option
-
-
-Douglas Gilbert has written yet another useful document at
-
 http://www.torque.net/scsi/SCSI-2.4-HOWTO/ which
 discusses the Linux SCSI subsystem in 2.4.
 
index 23a4d98..b5cb911 100644 (file)
@@ -11,57 +11,53 @@ for NetBSD, FreeBSD, the GNU HURD, Windows 95/98/NT, OS/2 and RISC OS.
 Options
 =======
 
-When mounting an ext2 filesystem, the following options are accepted.
-Defaults are marked with (*).
+Most defaults are determined by the filesystem superblock, and can be
+set using tune2fs(8). Kernel-determined defaults are indicated by (*).
 
 bsddf                  (*)     Makes `df' act like BSD.
 minixdf                                Makes `df' act like Minix.
 
-barrier=1                      This enables/disables barriers. barrier=0 disables it,
-                               barrier=1 enables it.
-
-orlov                  (*)     This enables the new Orlov block allocator. It's
-                               enabled by default.
-
-oldalloc                       This disables the Orlov block allocator and
-                               enables the old block allocator. Orlov should
-                               have better performance, we'd like to get some
-                               feedback  if it's the contrary for you.
-
-user_xattr             (*)     Enables POSIX Extended Attributes. It's enabled by
-                               default, however you need to confifure its support
-                               (CONFIG_EXT2_FS_XATTR). This is neccesary if you want
-                               to use POSIX Acces Control Lists support. You can visit
-                               http://acl.bestbits.at to know more about POSIX Extended
-                               attributes.
-
-nouser_xattr                   Disables POSIX Extended Attributes.
-
-acl                    (*)     Enables POSIX Access Control Lists support. This is
-                               enabled by default, however you need to configure
-                               its support (CONFIG_EXT2_FS_POSIX_ACL). If you want
-                               to know more about ACLs visit http://acl.bestbits.at
-
-noacl                          This option disables POSIX Access Control List support.
-
+check                          Check block and inode bitmaps at mount time
+                               (requires CONFIG_EXT2_CHECK).
 check=none, nocheck    (*)     Don't do extra checking of bitmaps on mount
                                (check=normal and check=strict options removed)
 
 debug                          Extra debugging information is sent to the
                                kernel syslog.  Useful for developers.
 
-errors=continue                (*)     Keep going on a filesystem error.
+errors=continue                        Keep going on a filesystem error.
 errors=remount-ro              Remount the filesystem read-only on an error.
 errors=panic                   Panic and halt the machine if an error occurs.
 
 grpid, bsdgroups               Give objects the same group ID as their parent.
-nogrpid, sysvgroups    (*)     New objects have the group ID of their creator.
+nogrpid, sysvgroups            New objects have the group ID of their creator.
+
+nouid32                                Use 16-bit UIDs and GIDs.
+
+oldalloc                       Enable the old block allocator. Orlov should
+                               have better performance, we'd like to get some
+                               feedback if it's the contrary for you.
+orlov                  (*)     Use the Orlov block allocator.
+                               (See http://lwn.net/Articles/14633/ and
+                               http://lwn.net/Articles/14446/.)
 
 resuid=n                       The user ID which may use the reserved blocks.
-resgid=n                       The group ID which may use the reserved blocks. 
+resgid=n                       The group ID which may use the reserved blocks.
 
 sb=n                           Use alternate superblock at this location.
 
+user_xattr                     Enable "user." POSIX Extended Attributes
+                               (requires CONFIG_EXT2_FS_XATTR).
+                               See also http://acl.bestbits.at
+nouser_xattr                   Don't support "user." extended attributes.
+
+acl                            Enable POSIX Access Control Lists support
+                               (requires CONFIG_EXT2_FS_POSIX_ACL).
+                               See also http://acl.bestbits.at
+noacl                          Don't support POSIX ACLs.
+
+nobh                           Do not attach buffer_heads to file pagecache.
+
 grpquota,noquota,quota,usrquota        Quota options are silently ignored by ext2.
 
 
index bdedb9f..2b5a56a 100644 (file)
@@ -15,13 +15,15 @@ ufstype=type_of_ufs
        ufs manually by mount option ufstype. Possible values are:
 
        old     old format of ufs
-               default value, supported os read-only
+               default value, supported as read-only
 
        44bsd   used in FreeBSD, NetBSD, OpenBSD
-               supported os read-write
+               supported as read-write
+
+       ufs2    used in FreeBSD 5.x
+               supported as read-only
 
-       ufs2    used in FreeBSD 5.x
-               supported os read-only
+       5xbsd   synonym for ufs2
 
        sun     used in SunOS (Solaris)
                supported as read-write
@@ -29,6 +31,9 @@ ufstype=type_of_ufs
        sunx86  used in SunOS for Intel (Solarisx86)
                supported as read-write
 
+       hp      used in HP-UX
+               supported as read-only
+
        nextstep
                used in NextStep
                supported as read-only
@@ -46,7 +51,7 @@ POSSIBLE PROBLEMS
 =================
 
 There is still bug in reallocation of fragment, in file fs/ufs/balloc.c, 
-line 364. But it seem working on current buffer cache configuration.
+line 364. But it seems working on current buffer cache configuration.
 
 
 BUG REPORTS
index 5be10c9..3f318dd 100644 (file)
@@ -44,7 +44,7 @@ Opening a File                                                     <subsection>
 The VFS implements the open(2), stat(2), chmod(2) and similar system
 calls. The pathname argument is used by the VFS to search through the
 directory entry cache (dentry cache or "dcache"). This provides a very
-fast lookup mechanism to translate a pathname (filename) into a
+fast look-up mechanism to translate a pathname (filename) into a
 specific dentry.
 
 An individual dentry usually has a pointer to an inode. Inodes are the
@@ -64,7 +64,7 @@ resolve your pathname into a dentry, the VFS may have to resort to
 creating dentries along the way, and then loading the inode. This is
 done by looking up the inode.
 
-To lookup an inode (usually read from disc) requires that the VFS
+To look up an inode (usually read from disc) requires that the VFS
 calls the lookup() method of the parent directory inode. This method
 is installed by the specific filesystem implementation that the inode
 lives in. There will be more on this later.
@@ -286,7 +286,7 @@ otherwise noted.
        dentry). Here you will probably call d_instantiate() with the
        dentry and the newly created inode
 
-  lookup: called when the VFS needs to lookup an inode in a parent
+  lookup: called when the VFS needs to look up an inode in a parent
        directory. The name to look for is found in the dentry. This
        method must call d_add() to insert the found inode into the
        dentry. The "i_count" field in the inode structure should be
@@ -405,7 +405,10 @@ from device node to device driver (this is an unofficial kernel
 patch).
 
 
-struct dentry_operations                                              <section>
+Directory Entry Cache (dcache)                                        <section>
+------------------------------
+
+struct dentry_operations
 ========================
 
 This describes how a filesystem can overload the standard dentry
@@ -425,7 +428,7 @@ struct dentry_operations {
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
-       is called whenever a name lookup finds a dentry in the
+       is called whenever a name look-up finds a dentry in the
        dcache. Most filesystems leave this as NULL, because all their
        dentries in the dcache are valid
 
@@ -448,6 +451,9 @@ Each dentry has a pointer to its parent dentry, as well as a hash list
 of child dentries. Child dentries are basically like files in a
 directory.
 
+Directory Entry Cache APIs
+--------------------------
+
 There are a number of functions defined which permit a filesystem to
 manipulate dentries:
 
@@ -482,3 +488,184 @@ manipulate dentries:
        pointer is NULL, the dentry is called a "negative
        dentry". This function is commonly called when an inode is
        created for an existing negative dentry
+
+  d_lookup: look up a dentry given its parent and path name component
+       It looks up the child of that given name from the dcache
+       hash table. If it is found, the reference count is incremented
+       and the dentry is returned. The caller must use d_put()
+       to free the dentry when it finishes using it.
+
+
+RCU-based dcache locking model
+------------------------------
+
+On many workloads, the most common operation on dcache is
+to look up a dentry, given a parent dentry and the name
+of the child. Typically, for every open(), stat() etc.,
+the dentry corresponding to the pathname will be looked
+up by walking the tree starting with the first component
+of the pathname and using that dentry along with the next
+component to look up the next level and so on. Since it
+is a frequent operation for workloads like multiuser
+environments and webservers, it is important to optimize
+this path.
+
+Prior to 2.5.10, dcache_lock was acquired in d_lookup and thus
+in every component during path look-up. Since 2.5.10 onwards,
+fastwalk algorithm changed this by holding the dcache_lock
+at the beginning and walking as many cached path component
+dentries as possible. This signficantly decreases the number
+of acquisition of dcache_lock. However it also increases the
+lock hold time signficantly and affects performance in large
+SMP machines. Since 2.5.62 kernel, dcache has been using
+a new locking model that uses RCU to make dcache look-up
+lock-free.
+
+The current dcache locking model is not very different from the existing
+dcache locking model. Prior to 2.5.62 kernel, dcache_lock
+protected the hash chain, d_child, d_alias, d_lru lists as well
+as d_inode and several other things like mount look-up. RCU-based
+changes affect only the way the hash chain is protected. For everything
+else the dcache_lock must be taken for both traversing as well as
+updating. The hash chain updations too take the dcache_lock.
+The significant change is the way d_lookup traverses the hash chain,
+it doesn't acquire the dcache_lock for this and rely on RCU to
+ensure that the dentry has not been *freed*.
+
+
+Dcache locking details
+----------------------
+For many multi-user workloads, open() and stat() on files are
+very frequently occurring operations. Both involve walking
+of path names to find the dentry corresponding to the
+concerned file. In 2.4 kernel, dcache_lock was held
+during look-up of each path component. Contention and
+cacheline bouncing of this global lock caused significant
+scalability problems. With the introduction of RCU
+in linux kernel, this was worked around by making
+the look-up of path components during path walking lock-free.
+
+
+Safe lock-free look-up of dcache hash table
+===========================================
+
+Dcache is a complex data structure with the hash table entries
+also linked together in other lists. In 2.4 kernel, dcache_lock
+protected all the lists. We applied RCU only on hash chain
+walking. The rest of the lists are still protected by dcache_lock.
+Some of the important changes are :
+
+1. The deletion from hash chain is done using hlist_del_rcu() macro which
+   doesn't initialize next pointer of the deleted dentry and this
+   allows us to walk safely lock-free while a deletion is happening.
+
+2. Insertion of a dentry into the hash table is done using
+   hlist_add_head_rcu() which take care of ordering the writes -
+   the writes to the dentry must be visible before the dentry
+   is inserted. This works in conjuction with hlist_for_each_rcu()
+   while walking the hash chain. The only requirement is that
+   all initialization to the dentry must be done before hlist_add_head_rcu()
+   since we don't have dcache_lock protection while traversing
+   the hash chain. This isn't different from the existing code.
+
+3. The dentry looked up without holding dcache_lock by cannot be
+   returned for walking if it is unhashed. It then may have a NULL
+   d_inode or other bogosity since RCU doesn't protect the other
+   fields in the dentry. We therefore use a flag DCACHE_UNHASHED to
+   indicate unhashed  dentries and use this in conjunction with a
+   per-dentry lock (d_lock). Once looked up without the dcache_lock,
+   we acquire the per-dentry lock (d_lock) and check if the
+   dentry is unhashed. If so, the look-up is failed. If not, the
+   reference count of the dentry is increased and the dentry is returned.
+
+4. Once a dentry is looked up, it must be ensured during the path
+   walk for that component it doesn't go away. In pre-2.5.10 code,
+   this was done holding a reference to the dentry. dcache_rcu does
+   the same.  In some sense, dcache_rcu path walking looks like
+   the pre-2.5.10 version.
+
+5. All dentry hash chain updations must take the dcache_lock as well as
+   the per-dentry lock in that order. dput() does this to ensure
+   that a dentry that has just been looked up in another CPU
+   doesn't get deleted before dget() can be done on it.
+
+6. There are several ways to do reference counting of RCU protected
+   objects. One such example is in ipv4 route cache where
+   deferred freeing (using call_rcu()) is done as soon as
+   the reference count goes to zero. This cannot be done in
+   the case of dentries because tearing down of dentries
+   require blocking (dentry_iput()) which isn't supported from
+   RCU callbacks. Instead, tearing down of dentries happen
+   synchronously in dput(), but actual freeing happens later
+   when RCU grace period is over. This allows safe lock-free
+   walking of the hash chains, but a matched dentry may have
+   been partially torn down. The checking of DCACHE_UNHASHED
+   flag with d_lock held detects such dentries and prevents
+   them from being returned from look-up.
+
+
+Maintaining POSIX rename semantics
+==================================
+
+Since look-up of dentries is lock-free, it can race against
+a concurrent rename operation. For example, during rename
+of file A to B, look-up of either A or B must succeed.
+So, if look-up of B happens after A has been removed from the
+hash chain but not added to the new hash chain, it may fail.
+Also, a comparison while the name is being written concurrently
+by a rename may result in false positive matches violating
+rename semantics.  Issues related to race with rename are
+handled as described below :
+
+1. Look-up can be done in two ways - d_lookup() which is safe
+   from simultaneous renames and __d_lookup() which is not.
+   If __d_lookup() fails, it must be followed up by a d_lookup()
+   to correctly determine whether a dentry is in the hash table
+   or not. d_lookup() protects look-ups using a sequence
+   lock (rename_lock).
+
+2. The name associated with a dentry (d_name) may be changed if
+   a rename is allowed to happen simultaneously. To avoid memcmp()
+   in __d_lookup() go out of bounds due to a rename and false
+   positive comparison, the name comparison is done while holding the
+   per-dentry lock. This prevents concurrent renames during this
+   operation.
+
+3. Hash table walking during look-up may move to a different bucket as
+   the current dentry is moved to a different bucket due to rename.
+   But we use hlists in dcache hash table and they are null-terminated.
+   So, even if a dentry moves to a different bucket, hash chain
+   walk will terminate. [with a list_head list, it may not since
+   termination is when the list_head in the original bucket is reached].
+   Since we redo the d_parent check and compare name while holding
+   d_lock, lock-free look-up will not race against d_move().
+
+4. There can be a theoritical race when a dentry keeps coming back
+   to original bucket due to double moves. Due to this look-up may
+   consider that it has never moved and can end up in a infinite loop.
+   But this is not any worse that theoritical livelocks we already
+   have in the kernel.
+
+
+Important guidelines for filesystem developers related to dcache_rcu
+====================================================================
+
+1. Existing dcache interfaces (pre-2.5.62) exported to filesystem
+   don't change. Only dcache internal implementation changes. However
+   filesystems *must not* delete from the dentry hash chains directly
+   using the list macros like allowed earlier. They must use dcache
+   APIs like d_drop() or __d_drop() depending on the situation.
+
+2. d_flags is now protected by a per-dentry lock (d_lock). All
+   access to d_flags must be protected by it.
+
+3. For a hashed dentry, checking of d_count needs to be protected
+   by d_lock.
+
+
+Papers and other documentation on dcache locking
+================================================
+
+1. Scaling dcache with RCU (http://linuxjournal.com/article.php?sid=7124).
+
+2. http://lse.sourceforge.net/locking/dcache/dcache.html
index 99d3ad3..6fb10fc 100644 (file)
@@ -13,15 +13,20 @@ LILO configuration options (Thinkpad users, read this)
  The floppy driver is configured using the 'floppy=' option in
 lilo. This option can be typed at the boot prompt, or entered in the
 lilo configuration file.
- Example: If your kernel is called linux-2.2.13, type the following line
+
+ Example: If your kernel is called linux-2.6.9, type the following line
 at the lilo boot prompt (if you have a thinkpad):
- linux-2.2.13 floppy=thinkpad
+
+ linux-2.6.9 floppy=thinkpad
+
 You may also enter the following line in /etc/lilo.conf, in the description
-of linux-2.2.13:
+of linux-2.6.9:
+
  append = "floppy=thinkpad"
 
  Several floppy related options may be given, example:
- linux-2.2.13 floppy=daring floppy=two_fdc
+
+ linux-2.6.9 floppy=daring floppy=two_fdc
  append = "floppy=daring floppy=two_fdc"
 
  If you give options both in the lilo config file and on the boot
@@ -29,17 +34,25 @@ prompt, the option strings of both places are concatenated, the boot
 prompt options coming last. That's why there are also options to
 restore the default behavior.
 
+
+Module configuration options
+============================
+
  If you use the floppy driver as a module, use the following syntax:
- insmod floppy <options>
+modprobe floppy <options>
 
 Example:
- insmod floppy daring two_fdc
+ modprobe floppy omnibook messages
+
+ If you need certain options enabled every time you load the floppy driver,
+you can put:
+
+ options floppy omnibook messages
+
+in /etc/modprobe.conf.
 
- Some versions of insmod are buggy in one way or another. If you have
-any problems (options not being passed correctly, segfaults during
-insmod), first check whether there is a more recent version.
 
- The floppy related options include:
+ The floppy driver related options are:
 
  floppy=asus_pci
        Sets the bit mask to allow only units 0 and 1. (default)
@@ -99,7 +112,7 @@ insmod), first check whether there is a more recent version.
        master arbitration error" messages from your Ethernet card (or
        from other devices) while accessing the floppy.
 
- floppy=fifo
+ floppy=usefifo
        Enables the FIFO. (default)
 
  floppy=<threshold>,fifo_depth
@@ -110,6 +123,7 @@ insmod), first check whether there is a more recent version.
        lower, the interrupt latency should be lower too (faster
        processor). The benefit of a lower threshold is less
        interrupts.
+
        To tune the fifo threshold, switch on over/underrun messages
        using 'floppycontrol --messages'. Then access a floppy
        disk. If you get a huge amount of "Over/Underrun - retrying"
@@ -120,6 +134,7 @@ insmod), first check whether there is a more recent version.
        fifo values without rebooting the machine for each test. Note
        that you need to do 'floppycontrol --messages' every time you
        re-insert the module.
+
        Usually, tuning the fifo threshold should not be needed, as
        the default (0xa) is reasonable.
 
@@ -128,6 +143,7 @@ insmod), first check whether there is a more recent version.
        you have more than two floppy drives (only two can be
        described in the physical CMOS), or if your BIOS uses
        non-standard CMOS types. The CMOS types are:
+
                0 - Use the value of the physical CMOS
                1 - 5 1/4 DD
                2 - 5 1/4 HD
@@ -136,6 +152,7 @@ insmod), first check whether there is a more recent version.
                5 - 3 1/2 ED
                6 - 3 1/2 ED
               16 - unknown or not installed
+
        (Note: there are two valid types for ED drives. This is because 5 was
        initially chosen to represent floppy *tapes*, and 6 for ED drives.
        AMI ignored this, and used 5 for ED drives. That's why the floppy
@@ -188,7 +205,6 @@ insmod), first check whether there is a more recent version.
           in some more extreme cases."
 
 
-
 Supporting utilities and additional documentation:
 ==================================================
 
@@ -219,3 +235,11 @@ sure to mention also the type of the filesystem in the subject line.
  Be sure to read the FAQ before mailing/posting any bug reports!
 
  Alain
+
+Changelog
+=========
+
+10-30-2004 :   Cleanup, updating, add reference to module configuration.
+               James Nelson <james4765@gmail.com>
+
+6-3-2000 :     Original Document
index 9cc814a..7d8bb33 100644 (file)
@@ -2,26 +2,21 @@ Intro
 =====
 
 This file describes some issues involved when using the "ftape"
-floppy tape device driver that comes with the Linux kernel. This
-document deals with ftape-3.04 and later. Please read the section
-"Changes" for the most striking differences between version 3.04 and
-2.08; the latter was the version of ftape delivered with the kernel
-until kernel version 2.0.30 and 2.1.57. ftape-3.x developed as the
-re-unification of ftape-2.x and zftape. zftape was developed in
-parallel with the stock ftape-2.x driver sharing the same hardware
-support but providing an enhanced file system interface. zftape also
-provided user transparent block-wise on-the-fly compression (regard it
-as a feature or bug of zftape).
+floppy tape device driver that comes with the Linux kernel.
 
 ftape has a home page at
 
-http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape
+http://ftape.dot-heine.de/
 
 which contains further information about ftape. Please cross check
 this WWW address against the address given (if any) in the MAINTAINERS
 file located in the top level directory of the Linux kernel source
 tree.
 
+NOTE: This is an unmaintained set of drivers, and it is not guaranteed to work.
+If you are interested in taking over maintenance, contact Claus-Justus Heine
+<ch@dot-heine.de>, the former maintainer.
+
 Contents
 ========
 
@@ -31,9 +26,8 @@ A. Changes
    1. Goal
    2. I/O Block Size
    3. Write Access when not at EOD (End Of Data) or BOT (Begin Of Tape)
-   4. MTBSF - backspace over file mark and position at its EOT side
-   5. Formatting
-   6. Interchanging cartridges with other operating systems
+   4. Formatting
+   5. Interchanging cartridges with other operating systems
 
 B. Debugging Output
    1. Introduction
@@ -58,7 +52,7 @@ changed. Up to date documentation as well as recent development
 versions of ftape and useful links to related topics can be found at
 the ftape home page at
 
-http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape
+http://ftape.dot-heine.de/
 
 *******************************************************************************
 
@@ -70,7 +64,7 @@ A. Changes
    The goal of all that incompatibilities was to give ftape an interface
    that resembles the interface provided by SCSI tape drives as close
    as possible. Thus any Unix backup program that is known to work
-   with SCSI tape drives should also work with ftape-3.04 and above.
+   with SCSI tape drives should also work.
 
    The concept of a fixed block size for read/write transfers is
    rather unrelated to this SCSI tape compatibility at the file system
@@ -81,14 +75,8 @@ A. Changes
 
 2. I/O Block Size
    ~~~~~~~~~~~~~~
-   The probably most striking difference between ftape-2.x and
-   ftape-3.x with the zftape file system interface is the concept of a
-   fixed block size: data must be written to or read from the tape in
-   multiples of a fixed block size. The block size defaults to 10k
-   which is the default block size of GNU tar. While this is quite
-   usual for SCSI tapes (block size of 32k?) and the QIC-150 driver
-   `./drivers/char/tpqic02.c' ftape-2.x allowed data to be written in
-   arbitrary portions to the tape.
+   The block size defaults to 10k which is the default block size of
+   GNU tar.
 
    The block size can be tuned either during kernel configuration or
    at runtime with the MTIOCTOP ioctl using the MTSETBLK operation
@@ -109,53 +97,41 @@ A. Changes
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    zftape (the file system interface of ftape-3.x) denies write access
    to the tape cartridge when it isn't positioned either at BOT or
-   EOD. This inconvenience has been introduced as it was reported that
-   the former behavior of ftape-2.x which allowed write access at
-   arbitrary locations already has caused data loss with some backup
-   programs.
-
-4. MTBSF - backspace over file mark and position at its EOT side
-   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-   ftape-2.x didn't handle the MTBSF tape operation correctly. A MTBSF
-   call (i.e. "mt -f /dev/nqft0 bsf #COUNT") should space over #COUNT
-   file marks and then position at the EOT tape side of the file
-   mark. This has to be taken literally, i.e. "mt -f /dev/nqft0 bsf 1"
-   should simply position at the start of the current volume.
-
-5. Formatting
+   EOD.
+
+4. Formatting
    ~~~~~~~~~~
-   ftape-3.x DOES support formatting of floppy tape cartridges. You
-   need the `ftformat' program that is shipped with the modules version
-   of ftape-3.x. Please get the latest version of ftape from
+   ftape DOES support formatting of floppy tape cartridges. You need the
+   `ftformat' program that is shipped with the modules version of ftape.
+   Please get the latest version of ftape from
 
    ftp://sunsite.unc.edu/pub/Linux/kernel/tapes
 
    or from the ftape home page at
 
-   http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape
+   http://ftape.dot-heine.de/
 
    `ftformat' is contained in the `./contrib/' subdirectory of that
    separate ftape package.
 
-6. Interchanging cartridges with other operating systems
+5. Interchanging cartridges with other operating systems
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
    The internal emulation of Unix tape device file marks has changed
-   completely. ftape-3.x now uses the volume table segment as specified
+   completely. ftape now uses the volume table segment as specified
    by the QIC-40/80/3010/3020/113 standards to emulate file marks. As
    a consequence there is limited support to interchange cartridges
    with other operating systems.
 
    To be more precise: ftape will detect volumes written by other OS's
    programs and other OS's programs will detect volumes written by
-   ftape-3.x.
+   ftape.
 
    However, it isn't possible to extract the data dumped to the tape
-   by some MSDOG program with ftape-3.x. This exceeds the scope of a
+   by some MSDOS program with ftape. This exceeds the scope of a
    kernel device driver. If you need such functionality, then go ahead
-   and write a user space utility that is able to do
-   that. ftape-3.x/zftape already provides all kernel level support
-   necessary to do that.
+   and write a user space utility that is able to do that. ftape already
+   provides all kernel level support necessary to do that.
 
 *******************************************************************************
 
@@ -200,7 +176,7 @@ B. Debugging Output
 
    ii) trim the debugging output at module load time with
 
-       insmod ftape.o ft_tracing=#DBGLVL
+       modprobe ftape ft_tracing=#DBGLVL
 
        Of course, this applies only if you have configured ftape to be
        compiled as a module.
@@ -240,7 +216,7 @@ C. Boot and load time configuration
 2. Module load time parameters
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Module parameters can be specified either directly when invoking
-   the program 'insmod' at the shell prompt:
+   the program 'modprobe' at the shell prompt:
 
    modprobe ftape ft_tracing=4
 
@@ -277,6 +253,12 @@ C. Boot and load time configuration
        line documentation provided during that kernel configuration
        process.
 
+       ft_probe_fc10 is set to a non-zero value if you wish for ftape to
+       probe for a Colorado FC-10 or FC-20 controller.
+
+       ft_mach2 is set to a non-zero value if you wish for ftape to probe
+       for a Mountain MACH-2 controller.
+
         module                 |  kernel command line
         -----------------------|----------------------
         ft_fdc_base=BASE       |  ftape=BASE,ioport
@@ -316,10 +298,10 @@ D. Support and contacts
    page to query for the most recent documentation, related work and
    development versions of ftape.
 
+   Changelog:
+   ==========
+
+~1996:         Original Document
 
- LocalWords:  ftape Linux zftape http www rwth aachen LBFM claus EOD config
- LocalWords:  datarate LocalWords BOT MTBSF EOT HOWTO QIC tpqic menuconfig
- LocalWords:  MTIOCTOP MTSETBLK mt dev qft setblk BLKSZ bsf zftape's xconfig
- LocalWords:  nqft ftformat ftp sunsite unc edu contrib ft MSDOG fdc
- LocalWords:  dma setdensity DBGLVL insmod lilo LI nux ader conf txt
- LocalWords:  modprobe IRQ BOOL ioport irq fc mach THR
+10-24-2004:    General cleanup and updating, noting additional module options.
+               James Nelson <james4765@gmail.com>
index 20be482..bb58c36 100644 (file)
@@ -67,72 +67,3 @@ Driver details:
 
        Special thanks to Matt Sottek.  I did the "guts", he
        did the "brains" and all the testing.
-
-Change history:
-
-       Version 1.0.0:
-       * Merge Intel, AMD, VIA RNG drivers into one.
-         Further changelog in BitKeeper.
-
-       Version 0.9.8:
-       * Support other i8xx chipsets by adding 82801E detection
-       * 82801DB detection is the same as for 82801CA.
-
-       Version 0.9.7:
-       * Support other i8xx chipsets too (by adding 82801BA(M) and
-         82801CA(M) detection)
-
-       Version 0.9.6:
-       * Internal driver cleanups, prep for 1.0.0 release.
-
-       Version 0.9.5:
-       * Rip out entropy injection via timer.  It never ever worked,
-         and a better solution (rngd) is now available.
-
-       Version 0.9.4:
-       * Fix: Remove request_mem_region
-       * Fix: Horrible bugs in FIPS calculation and test execution
-
-       Version 0.9.3:
-       * Clean up rng_read a bit.
-       * Update i810_rng driver Web site URL.
-       * Increase default timer interval to 4 samples per second.
-       * Abort if mem region is not available.
-       * BSS zero-initialization cleanup.
-       * Call misc_register() from rng_init_one.
-       * Fix O_NONBLOCK to occur before we schedule.
-
-       Version 0.9.2:
-       * Simplify open blocking logic
-
-       Version 0.9.1:
-       * Support i815 chipsets too (Matt Sottek)
-       * Fix reference counting when statically compiled (prumpf)
-       * Rewrite rng_dev_read (prumpf)
-       * Make module races less likely (prumpf)
-       * Small miscellaneous bug fixes (prumpf)
-       * Use pci table for PCI id list
-
-       Version 0.9.0:
-       * Don't register a pci_driver, because we are really
-         using PCI bridge vendor/device ids, and someone
-         may want to register a driver for the bridge. (bug fix)
-       * Don't let the usage count go negative (bug fix)
-       * Clean up spinlocks (bug fix)
-       * Enable PCI device, if necessary (bug fix)
-       * iounmap on module unload (bug fix)
-       * If RNG chrdev is already in use when open(2) is called,
-         sleep until it is available.
-       * Remove redundant globals rng_allocated, rng_use_count
-       * Convert numeric globals to unsigned
-       * Module unload cleanup
-
-       Version 0.6.2:
-       * Clean up spinlocks.  Since we don't have any interrupts
-         to worry about, but we do have a timer to worry about,
-         we use spin_lock_bh everywhere except the timer function
-         itself.
-       * Fix module load/unload.
-       * Fix timer function and h/w enable/disable logic
-       * New timer interval sysctl
-       * Clean up sysctl names
index 4fe882c..09d6cda 100644 (file)
@@ -3,7 +3,7 @@ possible to access all devices on an adapter from userspace, through
 the /dev interface. You need to load module i2c-dev for this.
 
 Each registered i2c adapter gets a number, counting from 0. You can
-examine /proc/bus/i2c to see what number corresponds to which adapter.
+examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
 I2C device files are character device files with major device number 89
 and a minor device number corresponding to the number assigned as 
 explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ..., 
@@ -19,7 +19,7 @@ Yes, I know, you should never include kernel header files, but until glibc
 knows about i2c, there is not much choice.
 
 Now, you have to decide which adapter you want to access. You should
-inspect /proc/bus/i2c to decide this. Adapter numbers are assigned
+inspect /sys/class/i2c-dev/ to decide this. Adapter numbers are assigned
 somewhat dynamically, so you can not even assume /dev/i2c-0 is the
 first adapter.
 
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.
+
index 3e74dae..3464005 100644 (file)
@@ -135,18 +135,44 @@ fan[1-3]_div      Fan divisor.
                Note that this is actually an internal clock divisor, which
                affects the measurable speed range, not the read value.
 
-fan[1-3]_pwm   Pulse width modulation fan control.
+*******
+* PWM *
+*******
+
+pwm[1-3]       Pulse width modulation fan control.
                Integer value in the range 0 to 255
                Read/Write
                255 is max or 100%.
 
-fan[1-3]_pwm_enable
+pwm[1-3]_enable
                Switch PWM on and off.
                Not always present even if fan*_pwm is.
                0 to turn off
-               1 to turn on
+               1 to turn on in manual mode
+               2 to turn on in automatic mode
                Read/Write
 
+pwm[1-*]_auto_channels_temp
+               Select which temperature channels affect this PWM output in
+               auto mode. Bitfield, 1 is temp1, 2 is temp2, 4 is temp3 etc...
+               Which values are possible depend on the chip used.
+
+pwm[1-*]_auto_point[1-*]_pwm
+pwm[1-*]_auto_point[1-*]_temp
+pwm[1-*]_auto_point[1-*]_temp_hyst
+               Define the PWM vs temperature curve. Number of trip points is
+               chip-dependent. Use this for chips which associate trip points
+               to PWM output channels.
+
+OR
+
+temp[1-*]_auto_point[1-*]_pwm
+temp[1-*]_auto_point[1-*]_temp
+temp[1-*]_auto_point[1-*]_temp_hyst
+               Define the PWM vs temperature curve. Number of trip points is
+               chip-dependent. Use this for chips which associate trip points
+               to temperature channels.
+
 
 ****************
 * Temperatures *
index a454212..011e920 100644 (file)
@@ -24,22 +24,24 @@ all clients from it. Remember, a driver structure contains general access
 routines, a client structure specific information like the actual I2C
 address.
 
-  static struct i2c_driver foo_driver = {
-    .owner          = THIS_MODULE,
-    .name           = "Foo version 2.3 driver",
-    .id             = I2C_DRIVERID_FOO, /* usually from i2c-id.h */
-    .flags          = I2C_DF_NOTIFY,
-    .attach_adapter = &foo_attach_adapter,
-    .detach_client  = &foo_detach_client,
-    .command        = &foo_command /* may be NULL */
-  }
+static struct i2c_driver foo_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "Foo version 2.3 driver",
+       .id             = I2C_DRIVERID_FOO, /* from i2c-id.h, optional */
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = &foo_attach_adapter,
+       .detach_client  = &foo_detach_client,
+       .command        = &foo_command /* may be NULL */
+}
  
 The name can be chosen freely, and may be upto 40 characters long. Please
 use something descriptive here.
 
-The id should be a unique ID. The range 0xf000 to 0xffff is reserved for
-local use, and you can use one of those until you start distributing the
-driver. Before you do that, contact the i2c authors to get your own ID(s).
+If used, the id should be a unique ID. The range 0xf000 to 0xffff is
+reserved for local use, and you can use one of those until you start
+distributing the driver, at which time you should contact the i2c authors
+to get your own ID(s). Note that most of the time you don't need an ID
+at all so you can just omit it.
 
 Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This
 means that your driver will be notified when new adapters are found.
@@ -569,7 +571,7 @@ the driver module is usually enough.
      have to be cleaned up! */
   static int __initdata foo_initialized = 0;
 
-  int __init foo_init(void)
+  static int __init foo_init(void)
   {
     int res;
     printk("foo version %s (%s)\n",FOO_VERSION,FOO_DATE);
@@ -583,41 +585,27 @@ the driver module is usually enough.
     return 0;
   }
 
-  int __init foo_cleanup(void)
+  void foo_cleanup(void)
   {
-    int res;
     if (foo_initialized == 1) {
       if ((res = i2c_del_driver(&foo_driver))) {
         printk("foo: Driver registration failed, module not removed.\n");
-        return res;
+        return;
       }
       foo_initialized --;
     }
-    return 0;
   }
 
-  #ifdef MODULE
-
   /* Substitute your own name and email address */
   MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
   MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
 
-  int init_module(void)
-  {
-    return foo_init();
-  }
-
-  int cleanup_module(void)
-  {
-    return foo_cleanup();
-  }
-
-  #endif /* def MODULE */
+  module_init(foo_init);
+  module_exit(foo_cleanup);
 
 Note that some functions are marked by `__init', and some data structures
-by `__init_data'. If this driver is compiled as part of the kernel (instead
-of as a module), those functions and structures can be removed after
-kernel booting is completed.
+by `__init_data'.  Hose functions and structures can be removed after
+kernel booting (or module loading) is completed.
 
 Command function
 ================
@@ -688,14 +676,26 @@ SMBus communication
   extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
   extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
                                        u8 command, u16 value);
-  extern s32 i2c_smbus_process_call(struct i2c_client * client,
-                                    u8 command, u16 value);
-  extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
-                                       u8 command, u8 *values);
   extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
                                         u8 command, u8 length,
                                         u8 *values);
 
+These ones were removed in Linux 2.6.10 because they had no users, but could
+be added back later if needed:
+
+  extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
+                                           u8 command, u8 *values);
+  extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
+                                       u8 command, u8 *values);
+  extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
+                                            u8 command, u8 length,
+                                            u8 *values);
+  extern s32 i2c_smbus_process_call(struct i2c_client * client,
+                                    u8 command, u16 value);
+  extern s32 i2c_smbus_block_process_call(struct i2c_client *client,
+                                          u8 command, u8 length,
+                                          u8 *values)
+
 All these transactions return -1 on failure. The 'write' transactions 
 return 0 on success; the 'read' transactions return the read value, except 
 for read_block, which returns the number of values read. The block buffers 
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
+
index 58853a4..12c7a2f 100644 (file)
@@ -248,13 +248,6 @@ Summary of ide driver parameters for kernel command line
                          allowing ide-floppy, ide-tape, and ide-cdrom|writers
                          to use ide-scsi emulation on a device specific option.
 
- "hdx=stroke"          : Should you have a system w/ an AWARD Bios and your
-                         drives are larger than 32GB and it will not boot,
-                         one is required to perform a few OEM operations first.
-                         The option is called "stroke" because it allows one
-                         to "soft clip" the drive to work around a barrier
-                         limit.
-
  "idebus=xx"           : inform IDE driver of VESA/PCI bus speed in MHz,
                          where "xx" is between 20 and 66 inclusive,
                          used when tuning chipset PIO modes.
@@ -304,7 +297,7 @@ Summary of ide driver parameters for kernel command line
 
  "ide=reverse"         : formerly called to pci sub-system, but now local.
 
-The following are valid ONLY on ide0 (except dc4030), which usually corresponds
+The following are valid ONLY on ide0, which usually corresponds
 to the first ATA interface found on the particular host, and the defaults for
 the base,ctl ports must not be altered.
 
@@ -315,7 +308,7 @@ the base,ctl ports must not be altered.
  "ide0=qd65xx"         : probe/support qd65xx interface
  "ide0=ali14xx"                : probe/support ali14xx chipsets (ALI M1439/M1443/M1445)
  "ide0=umc8672"                : probe/support umc8672 chipsets
- "idex=dc4030"         : probe/support Promise DC4030VL interface
+
  "ide=doubler"         : probe/support IDE doublers on Amiga
 
 There may be more options than shown -- use the source, Luke!
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
+
+
index 1075e4d..2616a58 100644 (file)
@@ -6,7 +6,7 @@ This document describes the Linux kernel Makefiles.
 
        === 1 Overview
        === 2 Who does what
-       === 3 The kbuild Makefiles
+       === 3 The kbuild files
           --- 3.1 Goal definitions
           --- 3.2 Built-in object goals - obj-y
           --- 3.3 Loadable module goals - obj-m
@@ -101,11 +101,14 @@ These people need to know about all aspects of the kernel Makefiles.
 This document is aimed towards normal developers and arch developers.
 
 
-=== 3 The kbuild Makefiles
+=== 3 The kbuild files
 
 Most Makefiles within the kernel are kbuild Makefiles that use the
 kbuild infrastructure. This chapter introduce the syntax used in the
 kbuild makefiles.
+The preferred name for the kbuild files is 'Kbuild' but 'Makefile' will
+continue to be supported. All new developmen is expected to use the
+Kbuild filename.
 
 Section 3.1 "Goal definitions" is a quick intro, further chapters provide
 more details, with real examples.
@@ -707,15 +710,17 @@ When kbuild executes the following steps are followed (roughly):
        probe supported options:
 
                #arch/i386/Makefile
-               check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc \
-                           /dev/null\ > /dev/null 2>&1; then echo "$(1)"; \
-                           else echo "$(2)"; fi)
-               cflags-$(CONFIG_MCYRIXIII) += $(call check_gcc,\
-                                                    -march=c3,-march=i486)
 
-               CFLAGS += $(cflags-y)
+               ...
+               cflags-$(CONFIG_MPENTIUMII)     += $(call cc-option,\
+                                               -march=pentium2,-march=i686)
+               ...
+               # Disable unit-at-a-time mode ...
+               CFLAGS += $(call cc-option,-fno-unit-at-a-time)
+               ...
+
 
-       The above examples both utilise the trick that a config option expands
+       The first examples utilises the trick that a config option expands
        to 'y' when selected.
 
     CFLAGS_KERNEL      $(CC) options specific for built-in
@@ -997,6 +1002,21 @@ When kbuild executes the following steps are followed (roughly):
        option. When $(biarch) equals to y the expanded variables $(aflags-y)
        and $(cflags-y) will be assigned the values -a32 and -m32.
 
+    cc-option-align
+       gcc version >= 3.0 shifted type of options used to speify
+       alignment of functions, loops etc. $(cc-option-align) whrn used
+       as prefix to the align options will select the right prefix:
+       gcc < 3.00
+               cc-option-align = -malign
+       gcc >= 3.00
+               cc-option-align = -falign
+       
+       Example:
+               CFLAGS += $(cc-option-align)-functions=4
+
+       In the above example the option -falign-functions=4 is used for
+       gcc >= 3.00. For gcc < 3.00 -malign-functions=4 is used.
+       
     cc-version
        cc-version return a numerical version of the $(CC) compiler version.
        The format is <major><minor> where both are two digits. So for example
index b893320..c91caf7 100644 (file)
-For now this is a raw copy from the old Documentation/kbuild/modules.txt,
-which was removed in 2.6.0-test5.
-The information herein is correct but not complete.
-
-Installing modules in a non-standard location
----------------------------------------------
-When the modules needs to be installed under another directory
-the INSTALL_MOD_PATH can be used to prefix "/lib/modules" as seen
-in the following example:
-
-make INSTALL_MOD_PATH=/frodo modules_install
-
-This will install the modules in the directory /frodo/lib/modules.
-/frodo can be a NFS mounted filesystem on another machine, allowing
-out-of-the-box support for installation on remote machines.
-
-
-Compiling modules outside the official kernel
----------------------------------------------
-
-Often modules are developed outside the official kernel.  To keep up
-with changes in the build system the most portable way to compile a
-module outside the kernel is to use the kernel build system,
-kbuild. Use the following command-line:
-
-make -C path/to/kernel/src M=$PWD modules
-
-This requires that a makefile exits made in accordance to
-Documentation/kbuild/makefiles.txt. Read that file for more details on
-the build system.
-
-The following is a short summary of how to write your Makefile to get
-you up and running fast. Assuming your module will be called
-yourmodule.ko, your code should be in yourmodule.c and your Makefile
-should include
-
-obj-m := yourmodule.o
-
-If the code for your module is in multiple files that need to be
-linked, you need to tell the build system which files to compile. In
-the case of multiple files, none of these files can be named
-yourmodule.c because doing so would cause a problem with the linking
-step. Assuming your code exists in file1.c, file2.c, and file3.c and
-you want to build yourmodule.ko from them, your Makefile should
-include
-
-obj-m := yourmodule.o
-yourmodule-objs := file1.o file2.o file3.o
-
-Now for a final example to put it all together. Assuming the
-KERNEL_SOURCE environment variable is set to the directory where you
-compiled the kernel, a simple Makefile that builds yourmodule.ko as
-described above would look like
-
-# Tells the build system to build yourmodule.ko.
-obj-m := yourmodule.o
-
-# Tells the build system to build these object files and link them as
-# yourmodule.o, before building yourmodule.ko. This line can be left
-# out if all the code for your module is in one file, yourmodule.c. If
-# you are using multiple files, none of these files can be named
-# yourmodule.c.
-yourmodule-objs := file1.o file2.o file3.o
-
-# Invokes the kernel build system to come back to the current
-# directory and build yourmodule.ko.
-default:
-       make -C ${KERNEL_SOURCE} M=`pwd` modules
+
+In this document you will find information about:
+- how to build external modules
+- how to make your module use kbuild infrastructure
+- how kbuild will install a kernel
+- how to install modules in a non-standard location
+
+=== Table of Contents
+
+       === 1 Introduction
+       === 2 How to build external modules
+          --- 2.1 Building external modules
+          --- 2.2 Available targets
+          --- 2.3 Available options
+          --- 2.4 Preparing the kernel tree for module build
+       === 3. Example commands
+       === 4. Creating a kbuild file for an external module
+       === 5. Include files
+          --- 5.1 How to include files from the kernel include dir
+          --- 5.2 External modules using an include/ dir
+       === 6. Module installation
+          --- 6.1 INSTALL_MOD_PATH
+          --- 6.2 INSTALL_MOD_DIR
+       === 7. Module versioning
+       === 8. Tips & Tricks
+          --- 8.1 Testing for CONFIG_FOO_BAR
+
+
+
+=== 1. Introduction
+
+kbuild includes functionality for building modules both
+within the kernel source tree and outside the kernel source tree.
+The latter is usually referred to as external modules and is used
+both during development and for modules that are not planned to be
+included in the kernel tree.
+
+What is covered within this file is mainly information to authors
+of modules. The author of an external modules should supply
+a makefile that hides most of the complexity so one only has to type
+'make' to buld the module. A complete example will be present in
+chapter Â¤. Creating a kbuild file for an external module".
+
+
+=== 2. How to build external modules
+
+kbuild offers functionality to build external modules, with the
+prerequisite that there is a pre-built kernel available with full source.
+A subset of the targets available when building the kernel is available
+when building an external module.
+
+--- 2.1 Building external modules
+
+       Use the following command to build an external module:
+
+               make -C <path-to-kernel> M=`pwd`
+
+       For the running kernel use:
+               make -C /lib/modules/`uname -r`/build M=`pwd`
+
+       For the above command to succeed the kernel must have been built with
+       modules enabled.
+
+       To install the modules that were just built:
+
+               make -C <path-to-kernel> M=`pwd` modules_install
+
+       More complex examples later, the above should get you going.
+
+--- 2.2 Available targets
+
+       $KDIR refers to path to kernel source top-level directory
+
+       make -C $KDIR M=`pwd`
+               Will build the module(s) located in current directory.
+               All output files will be located in the same directory
+               as the module source.
+               No attempts are made to update the kernel source, and it is
+               a precondition that a successful make has been executed
+               for the kernel.
+
+       make -C $KDIR M=`pwd` modules
+               The modules target is implied when no target is given.
+               Same functionality as if no target was specified.
+               See description above.
+
+       make -C $KDIR M=$PWD modules_install
+               Install the external module(s).
+               Installation default is in /lib/modules/<kernel-version>/extra,
+               but may be prefixed with INSTALL_MOD_PATH - see separate chater.
+
+       make -C $KDIR M=$PWD clean
+               Remove all generated files for the module - the kernel
+               source directory is not moddified.
+
+       make -C $KDIR M=`pwd` help
+               help will list the available target when building external
+               modules.
+
+--- 2.3 Available options:
+
+       $KDIR refer to path to kernel src
+
+       make -C $KDIR
+               Used to specify where to find the kernel source.
+               '$KDIR' represent the directory where the kernel source is.
+               Make will actually change directory to the specified directory
+               when executed but change back when finished.
+
+       make -C $KDIR M=`pwd`
+               M= is used to tell kbuild that an external module is
+               being built.
+               The option given to M= is the directory where the external
+               module (kbuild file) is located.
+               When an external module is being built only a subset of the
+               usual targets are available.
+
+       make -C $KDIR SUBDIRS=`pwd`
+               Same as M=. The SUBDIRS= syntax is kept for backwards
+               compatibility.
+
+--- 2.4 Preparing the kernel tree for module build
+
+       To make sure the kernel contains the information required to
+       build external modules the target 'modules_prepare' must be used.
+       'module_prepare' solely exists as a simple way to prepare
+       a kernel for building external modules.
+       Note: modules_prepare will not build Module.symvers even if
+             CONFIG_MODULEVERSIONING is set.
+             Therefore a full kernel build needs to be executed to make
+             module versioning work.
+
+
+=== 3. Example commands
+
+This example shows the actual commands to be executed when building
+an external module for the currently running kernel.
+In the example below the distribution is supposed to use the
+facility to locate output files for a kernel compile in a different
+directory than the kernel source - but the examples will also work
+when the source and the output files are mixed in the same directory.
+
+# Kernel source
+/lib/modules/<kernel-version>/source -> /usr/src/linux-<version>
+
+# Output from kernel compile
+/lib/modules/<kernel-version>/build -> /usr/src/linux-<version>-up
+
+Change to the directory where the kbuild file is located and execute
+the following commands to build the module:
+
+       cd /home/user/src/module
+       make -C /usr/src/`uname -r`/source            \
+               O=/lib/modules/`uname-r`/build        \
+               M=`pwd`
+
+Then to install the module use the following command:
+
+       make -C /usr/src/`uname -r`/source            \
+               O=/lib/modules/`uname-r`/build        \
+               M=`pwd`                               \
+               modules_install
+
+If one looks closely you will see that this is the same commands as
+listed before - with the directories spelled out.
+
+The above are rather long commands, and the following chapter
+lists a few tricks to make it all easier.
+
+
+=== 4. Creating a kbuild file for an external module
+
+kbuild is the build system for the kernel, and external modules
+must use kbuild to stay compatible with changes in the build system
+and to pick up the right flags to gcc etc.
+
+The kbuild file used as input shall follow the syntax described
+in Documentation/kbuild/makefiles.txt. This chapter will introduce a few
+more tricks to be used when dealing with external modules.
+
+In the following a Makefile will be created for a module with the
+following files:
+       8123_if.c
+       8123_if.h
+       8123_pci.c
+       8123_bin.o_shipped      <= Binary blob
+
+--- 4.1 Shared Makefile for module and kernel
+
+       An external module always includes a wrapper Makefile supporting
+       building the module using 'make' with no arguments.
+       The Makefile provided will most likely include additional
+       functionality such as test targets etc. and this part shall
+       be filtered away from kbuild since it may impact kbuild if
+       name clashes occurs.
+
+       Example 1:
+               --> filename: Makefile
+               ifneq ($(KERNELRELEASE),)
+               # kbuild part of makefile
+               obj-m  := 8123.o
+               8123-y := 8123_if.o 8123_pci.o 8123_bin.o
+
+               else
+               # Normal Makefile
+
+               KERNELDIR := /lib/modules/`uname -r`/build
+               all::
+                       $(MAKE) -C $KERNELDIR M=`pwd` $@
+
+               # Module specific targets
+               genbin:
+                       echo "X" > 8123_bini.o_shipped
+
+               endif
+
+       In example 1 the check for KERNELRELEASE is used to separate
+       the two parts of the Makefile. kbuild will only see the two
+       assignments whereas make will see everything except the two
+       kbuild assignments.
+
+       In recent versions of the kernel, kbuild will look for a file named
+       Kbuild and as second option look for a file named Makefile.
+       Utilising the Kbuild file makes us split up the Makefile in example 1
+       into two files as shown in example 2:
+
+       Example 2:
+               --> filename: Kbuild
+               obj-m  := 8123.o
+               8123-y := 8123_if.o 8123_pci.o 8123_bin.o
+
+               --> filename: Makefile
+               KERNELDIR := /lib/modules/`uname -r`/build
+               all::
+                       $(MAKE) -C $KERNELDIR M=`pwd` $@
+
+               # Module specific targets
+               genbin:
+                       echo "X" > 8123_bin_shipped
+
+
+       In example 2 we are down to two fairly simple files and for simple
+       files as used in this example the split is questionable. But some
+       external modules use Makefiles of several hundred lines and here it
+       really pays off to separate the kbuild part from the rest.
+       Example 3 shows a backward compatible version.
+
+       Example 3:
+               --> filename: Kbuild
+               obj-m  := 8123.o
+               8123-y := 8123_if.o 8123_pci.o 8123_bin.o
+
+               --> filename: Makefile
+               ifneq ($(KERNELRELEASE),)
+               include Kbuild
+               else
+               # Normal Makefile
+
+               KERNELDIR := /lib/modules/`uname -r`/build
+               all::
+                       $(MAKE) -C $KERNELDIR M=`pwd` $@
+
+               # Module specific targets
+               genbin:
+                       echo "X" > 8123_bin_shipped
+
+               endif
+
+               The trick here is to include the Kbuild file from Makefile so
+               if an older version of kbuild picks up the Makefile the Kbuild
+               file will be included.
+
+--- 4.2 Binary blobs included in a module
+
+       Some external modules needs to include a .o as a blob. kbuild
+       has support for this, but requires the blob file to be named
+       <filename>_shipped. In our example the blob is named
+       8123_bin.o_shipped and when the kbuild rules kick in the file
+       8123_bin.o is created as a simple copy off the 8213_bin.o_shipped file
+       with the _shipped part stripped of the filename.
+       This allows the 8123_bin.o filename to be used in the assignment to
+       the module.
+
+       Example 4:
+               obj-m  := 8123.o
+               8123-y := 8123_if.o 8123_pci.o 8123_bin.o
+
+       In example 4 there is no distinction between the ordinary .c/.h files
+       and the binary file. But kbuild will pick up different rules to create
+       the .o file.
+
+
+=== 5. Include files
+
+Include files are a necessity when a .c file uses something from another .c
+files (not strictly in the sense of .c but if good programming practice is
+used). Any module that consist of more than one .c file will have a .h file
+for one of the .c files. 
+- If the .h file only describes a module internal interface then the .h file
+  shall be placed in the same directory as the .c files.
+- If the .h files describe an interface used by other parts of the kernel
+  located in different directories, the .h files shall be located in
+  include/linux/ or other include/ directories as appropriate.
+
+One exception for this rule is larger subsystems that have their own directory
+under include/ such as include/scsi. Another exception is arch-specific
+.h files which are located under include/asm-$(ARCH)/*.
+
+External modules have a tendency to locate include files in a separate include/
+directory and therefore needs to deal with this in their kbuild file.
+
+--- 5.1 How to include files from the kernel include dir
+
+       When a module needs to include a file from include/linux/ then one
+       just uses:
+
+               #include <linux/modules.h>
+
+       kbuild will make sure to add options to gcc so the relevant
+       directories are searched.
+       Likewise for .h files placed in the same directory as the .c file.
+
+               #include "8123_if.h"
+
+       will do the job.
+
+--- 5.2 External modules using an include/ dir
+
+       External modules often locate their .h files in a separate include/
+       directory although this is not usual kernel style. When an external
+       module uses an include/ dir then kbuild needs to be told so.
+       The trick here is to use either EXTRA_CFLAGS (take effect for all .c
+       files) or CFLAGS_$F.o (take effect only for a single file).
+
+       In our example if we move 8123_if.h to a subdirectory named include/
+       the resulting Kbuild file would look like:
+
+               --> filename: Kbuild
+               obj-m  := 8123.o
+
+               EXTRA_CFLAGS := -Iinclude
+               8123-y := 8123_if.o 8123_pci.o 8123_bin.o
+
+       Note that in the assingment there is no space between -I and the path.
+       This is a kbuild limitation and no space must be present.
+
+
+=== 6. Module installation
+
+Modules which are included in the kernel is installed in the directory:
+
+       /lib/modules/$(KERNELRELEASE)/kernel
+
+External modules are installed in the directory:
+
+       /lib/modules/$(KERNELRELEASE)/extra
+
+--- 6.1 INSTALL_MOD_PATH
+
+       Above are the default directories, but as always some level of
+       customization is possible. One can prefix the path using the variable
+       INSTALL_MOD_PATH:
+
+               $ make INSTALL_MOD_PATH=/frodo modules_install
+               => Install dir: /frodo/lib/modules/$(KERNELRELEASE)/kernel
+
+       INSTALL_MOD_PATH may be set as an ordinary shell variable or as in the
+       example above be specified on the commandline when calling make.
+       INSTALL_MOD_PATH has effect both when installing modules included in
+       the kernel as well as when installing external modules.
+
+--- 6.2 INSTALL_MOD_DIR
+
+       When installing external modules they are default installed in a
+       directory under /lib/modules/$(KERNELRELEASE)/extra, but one may wish
+       to locate modules for a specific functionality in a separate
+       directory. For this purpose one can use INSTALL_MOD_DIR to specify an
+       alternative name than 'extra'.
+
+               $ make INSTALL_MOD_DIR=gandalf -C KERNELDIR \
+                       M=`pwd` modules_install
+               => Install dir: /lib/modules/$(KERNELRELEASE)/gandalf
+
+
+=== 7. Module versioning
+
+Module versioning are enabled by the CONFIG_MODVERSIONS tag.
+
+Module versioning is used as a simple ABI consistency check. The Module
+versioning creates a CRC value of the full prototype for an exported symbol and
+when a module is loaded/used then the CRC values contained in the kernel are
+compared with similar values in the module. If they are not equal then the
+kernel refuses to load the module.
+
+During a kernel build a file named Module.symvers will be generated. This
+file includes the symbol version of all symbols within the kernel. If the 
+Module.symvers file is saved from the last full kernel compile one does not
+have to do a full kernel compile to build a module version's compatible module.
+
+=== 8. Tips & Tricks
+
+--- 8.1 Testing for CONFIG_FOO_BAR
+
+       Modules often needs to check for certain CONFIG_ options to decide if
+       a specific feature shall be included in the module. When kbuild is used
+       this is done by referencing the CONFIG_ variable directly.
+
+               #fs/ext2/Makefile
+               obj-$(CONFIG_EXT2_FS) += ext2.o
+
+               ext2-y := balloc.o bitmap.o dir.o
+               ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
+
+       External modules have traditionally used grep to check for specific
+       CONFIG_ settings directly in .config. This usage is broken.
+       As introduced before external modules shall use kbuild when building
+       and therefore can use the same methods as in-kernel modules when testing
+       for CONFIG_ definitions.
+
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.
index 7af1709..2b3dedd 100644 (file)
@@ -21,6 +21,8 @@ systems.
 All of these problems can be addressed with the "mem=XXXM" boot option
 (where XXX is the size of RAM to use in megabytes).  
 It can also tell Linux to use less memory than is actually installed.
+If you use "mem=" on a machine with PCI, consider using "memmap=" to avoid
+physical address space collisions.
 
 See the documentation of your boot loader (LILO, loadlin, etc.) about
 how to pass options to the kernel.
@@ -44,7 +46,9 @@ Try:
        * Disabling the cache from the BIOS.
 
        * Try passing the "mem=4M" option to the kernel to limit
-         Linux to using a very small amount of memory.
+         Linux to using a very small amount of memory. Use "memmap="-option
+         together with "mem=" on systems with PCI to avoid physical address
+         space collisions.
 
 
 Other tricks:
index 0b2b705..e4b6c7a 100644 (file)
@@ -1,14 +1,16 @@
 Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
 ==============================================================
 
-March 15, 2004
+September 13, 2004
 
 
 Contents
 ========
 
 - In This Release
-- Supported Adapters
+- Identifying Your Adapter
+- Driver Configuration Parameters
+- Additional Configurations
 - Support
 
 
@@ -16,26 +18,140 @@ In This Release
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family of
-Adapters, version 3.x.x.  This driver includes support for Itanium(TM)-based 
-systems.
+Adapters, version 3.2.x.  This driver includes support for Itanium(TM)2 and
+EM64T systems.
 
 
-Supported Adapters
-==================
-
-To verify that your adapter is supported, find the board ID number on the 
-adapter. Look for a label that has a barcode and a number in the format 
-A12345-001. Match this to the list of numbers above.
+Identifying Your Adapter
+========================
 
 For more information on how to identify your adapter, go to the Adapter & 
 Driver ID Guide at:
 
   http://support.intel.com/support/network/adapter/pro100/21397.htm
 
-For the latest Intel PRO/100 network driver for Linux, see:
+For the latest Intel network drivers for Linux, refer to the following 
+website. In the search field, enter your adapter name or type, or use the 
+networking link on the left to search for your adapter:
 
   http://downloadfinder.intel.com/scripts-df/support_intel.asp
 
+Driver Configuration Parameters
+===============================
+
+The default value for each parameter is generally the recommended setting,
+unless otherwise noted.
+
+Rx Descriptors: Number of receive descriptors. A receive descriptor is a data 
+   structure that describes a receive buffer and its attributes to the network 
+   controller. The data in the descriptor is used by the controller to write 
+   data from the controller to host memory. In the 3.0.x driver the valid
+   range for this parameter is 64-256. The default value is 64. This parameter 
+   can be changed using the command 
+   ethtool -G eth? rx n, where n is the number of desired rx descriptors.
+
+Tx Descriptors: Number of transmit descriptors. A transmit descriptor is a
+   data structure that describes a transmit buffer and its attributes to the
+   network controller. The data in the descriptor is used by the controller to 
+   read data from the host memory to the controller. In the 3.0.x driver the 
+   valid range for this parameter is 64-256. The default value is 64. This 
+   parameter can be changed using the command 
+
+   ethtool -G eth? tx n, where n is the number of desired tx descriptors.
+
+Speed/Duplex: The driver auto-negotiates the link speed and duplex settings by 
+   default. Ethtool can be used as follows to force speed/duplex. 
+
+   ethtool -s eth?  autoneg off speed {10|100} duplex {full|half}
+
+   NOTE: setting the speed/duplex to incorrect values will cause the link to
+   fail.
+
+Event Log Message Level:  The driver uses the message level flag to log events 
+   to syslog. The message level can be set at driver load time. It can also be 
+   set using the command
+
+   ethtool -s eth? msglvl n
+
+Additional Configurations
+=========================
+
+  Configuring the Driver on Different Distributions
+  -------------------------------------------------
+
+  Configuring a network driver to load properly when the system is started is 
+  distribution dependent. Typically, the configuration process involves adding 
+  an alias line to /etc/modules.conf as well as editing other system startup 
+  scripts and/or configuration files.  Many popular Linux distributions ship 
+  with tools to make these changes for you. To learn the proper way to 
+  configure a network device for your system, refer to your distribution 
+  documentation. If during this process you are asked for the driver or module 
+  name, the name for the Linux Base Driver for the Intel PRO/100 Family of 
+  Adapters is e100.
+
+  As an example, if you install the e100 driver for two PRO/100 adapters 
+  (eth0 and eth1), add the following to modules.conf:
+
+       alias eth0 e100
+       alias eth1 e100
+
+  Viewing Link Messages
+  ---------------------
+  In order to see link messages and other Intel driver information on your 
+  console, you must set the dmesg level up to six. This can be done by 
+  entering the following on the command line before loading the e100 driver: 
+
+       dmesg -n 8
+
+  If you wish to see all messages issued by the driver, including debug 
+  messages, set the dmesg level to eight.
+
+  NOTE: This setting is not saved across reboots.
+
+  Ethtool
+  -------
+
+  The driver utilizes the ethtool interface for driver configuration and
+  diagnostics, as well as displaying statistical information.  Ethtool
+  version 1.6 or later is required for this functionality.
+
+  The latest release of ethtool can be found at:
+  http://sf.net/projects/gkernel.  
+
+  After ethtool is installed, ethtool-copy.h must be copied and renamed to
+  ethtool.h in your kernel source tree at <linux_kernel_src>/include/linux.  
+  Backup the original ethtool.h as needed before copying.  The driver then 
+  must be recompiled in order to take advantage of the latest ethtool 
+  features.
+
+  NOTE: This driver uses mii support from the kernel. As a result, when 
+  there is no link, ethtool will report speed/duplex to be 10/half.
+
+  NOTE: Ethtool 1.6 only supports a limited set of ethtool options. Support 
+  for a more complete ethtool feature set can be enabled by upgrading 
+  ethtool to ethtool-1.8.1. 
+
+  Enabling Wake on LAN* (WoL)
+  ---------------------------
+  WoL is provided through the Ethtool* utility. Ethtool is included with Red 
+  Hat* 8.0. For other Linux distributions, download and install Ethtool from 
+  the following website: http://sourceforge.net/projects/gkernel. 
+
+  For instructions on enabling WoL with Ethtool, refer to the Ethtool man
+  page.
+
+  WoL will be enabled on the system during the next shut down or reboot. For
+  this driver version, in order to enable WoL, the e100 driver must be 
+  loaded when shutting down or rebooting the system.
+
+  NAPI
+  ----
+
+  NAPI (Rx polling mode) is supported in the e100 driver. NAPI is enabled
+  or disabled based on the configuration of the kernel. 
+
+  See www.cyberus.ca/~hadi/usenix-paper.tgz for more information on NAPI.
 
 Support
 =======
index 9b2329f..794c925 100644 (file)
@@ -1,14 +1,14 @@
 Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
 ===============================================================
 
-January 8, 2003
+September 13, 2004
 
 
 Contents
 ========
 
 - In This Release
-- Supported Adapters
+- Identifying Your Adapter
 - Command Line Parameters
 - Speed and Duplex Configuration
 - Additional Configurations
@@ -20,63 +20,29 @@ In This Release
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
-of Adapters, version 5.0.x.  This driver includes support for 
-Itanium(TM)-based systems.
+of Adapters, version 5.x.x.  This driver includes support for Itanium(TM)2 
+and EM64T systems.
 
+For questions related to hardware requirements, refer to the documentation 
+supplied with your Intel PRO/1000 adapter. All hardware requirements listed 
+apply to use with Linux.
 
 Native VLANs are now available with supported kernels.
 
-
-Supported Adapters
-==================
-
-The following Intel network adapters are compatible with the drivers in this 
-release:
-
-   Controller  Adapter Name                         Board IDs
-   ----------  ------------                         ---------
-
-   82542       PRO/1000 Gigabit Server Adapter      700262-xxx, 717037-xxx
-
-   82543       PRO/1000 F Server Adapter            738640-xxx, A38888-xxx
-
-   82543       PRO/1000 T Server Adapter            A19845-xxx, A33948-xxx
-
-   82544       PRO/1000 XT Server Adapter           A51580-xxx
-
-   82544       PRO/1000 XF Server Adapter           A50484-xxx
-
-   82544       PRO/1000 T Desktop Adapter           A62947-xxx
-
-   82540       PRO/1000 MT Desktop Adapter          A78408-xxx
-   82541                                            C91016-xxx
-
-   82545       PRO/1000 MT Server Adapter           A92165-xxx
-
-   82546       PRO/1000 MT Dual Port Server Adapter A92111-xxx
-
-   82545       PRO/1000 MF Server Adapter           A91622-xxx
-
-   82545       PRO/1000 MF Server Adapter(LX)       A91624-xxx
-
-   82546       PRO/1000 MF Dual Port Server Adapter A91620-xxx
-
-
-
-To verify your Intel adapter is supported, find the board ID number on the 
-adapter. Look for a label that has a barcode and a number in the format  
-A12345-001. Match this to the list of numbers above.
+Identifying Your Adapter
+========================
 
 For more information on how to identify your adapter, go to the Adapter & 
 Driver ID Guide at:
 
     http://support.intel.com/support/network/adapter/pro100/21397.htm
 
-For the latest Intel network drivers for Linux, refer to the following
+For the latest Intel network drivers for Linux, refer to the following 
+website. In the search field, enter your adapter name or type, or use the 
+networking link on the left to search for your adapter:
 
     http://downloadfinder.intel.com/scripts-df/support_intel.asp
 
-
 Command Line Parameters
 =======================
 
@@ -92,27 +58,39 @@ For example, with two PRO/1000 PCI adapters, entering:
 
      insmod e1000 TxDescriptors=80,128
 
-loads the e1000 driver with 80 TX resources for the first adapter and 128 TX 
-resources for the second adapter.
+loads the e1000 driver with 80 TX descriptors for the first adapter and 128 TX 
+descriptors for the second adapter.
 
 The default value for each parameter is generally the recommended setting,
-unless otherwise noted.
+unless otherwise noted. Also, if the driver is statically built into the
+kernel, the driver is loaded with the default values for all the parameters.
+Ethtool can be used to change some of the parameters at runtime.
+
+    NOTES: For more information about the AutoNeg, Duplex, and Speed
+           parameters, see the "Speed and Duplex Configuration" section in 
+           this document.
 
-For more information about the AutoNeg, Duplex, and Speed parameters, see the
-"Speed and Duplex Configuration" section in this document.
+           For more information about the InterruptThrottleRate, RxIntDelay, 
+           TxIntDelay, RxAbsIntDelay, and TxAbsIntDelay parameters, see the 
+           application note at:
+           http://www.intel.com/design/network/applnots/ap450.htm
 
+           A descriptor describes a data buffer and attributes related to the 
+           data buffer. This information is accessed by the hardware.
 
 AutoNeg (adapters using copper connections only)
 Valid Range: 0x01-0x0F, 0x20-0x2F
 Default Value: 0x2F
     This parameter is a bit mask that specifies which speed and duplex
     settings the board advertises. When this parameter is used, the Speed and
-    Duplex parameters must not be specified.  
+    Duplex parameters must not be specified.
+    NOTE: Refer to the Speed and Duplex section of this readme for more 
+          information on the AutoNeg parameter.  
 
 Duplex (adapters using copper connections only)
 Valid Range: 0-2 (0=auto-negotiate, 1=half, 2=full)
 Default Value: 0
-    Defines the direction in which data is allowed to flow. Can by either one 
+    Defines the direction in which data is allowed to flow. Can be either one 
     or two-directional. If both Duplex and the link partner are set to auto-
     negotiate, the board auto-detects the correct duplex. If the link partner
     is forced (either full or half), Duplex defaults to half-duplex.
@@ -125,22 +103,46 @@ Default: Read flow control settings from the EEPROM
 
 InterruptThrottleRate
 Valid Range: 100-100000 (0=off, 1=dynamic)
-Default Value: 1
+Default Value: 8000
     This value represents the maximum number of interrupts per second the 
     controller generates. InterruptThrottleRate is another setting used in 
     interrupt moderation. Dynamic mode uses a heuristic algorithm to adjust 
     InterruptThrottleRate based on the current traffic load.
+Un-supported Adapters: InterruptThrottleRate is NOT supported by 82542, 82543
+    or 82544-based adapters.
 
     NOTE: InterruptThrottleRate takes precedence over the TxAbsIntDelay and 
           RxAbsIntDelay parameters. In other words, minimizing the receive 
           and/or transmit absolute delays does not force the controller to 
           generate more interrupts than what the Interrupt Throttle Rate 
           allows.
+    CAUTION: If you are using the Intel PRO/1000 CT Network Connection 
+             (controller 82547), setting InterruptThrottleRate to a value 
+             greater than 75,000, may hang (stop transmitting) adapters under 
+             certain network conditions. If this occurs a NETDEV WATCHDOG 
+             message is logged in the system event log. In addition, the 
+             controller is automatically reset, restoring the network 
+             connection. To eliminate the potential for the hang, ensure 
+             that InterruptThrottleRate is set no greater than 75,000 and is 
+             not set to 0.
+    NOTE: When e1000 is loaded with default settings and multiple adapters are 
+          in use simultaneously, the CPU utilization may increase non-linearly. 
+          In order to limit the CPU utilization without impacting the overall 
+          throughput, we recommend that you load the driver as follows:
+
+              insmod e1000.o InterruptThrottleRate=3000,3000,3000
+
+          This sets the InterruptThrottleRate to 3000 interrupts/sec for the 
+          first, second, and third instances of the driver. The range of 2000 to 
+          3000 interrupts per second works on a majority of systems and is a 
+          good starting point, but the optimal value will be platform-specific. 
+          If CPU utilization is not a concern, use RX_POLLING (NAPI) and default 
+          driver settings.
 
 RxDescriptors
 Valid Range: 80-256 for 82542 and 82543-based adapters
-             80-4096 for 82540, 82544, 82545, and 82546-based adapters
-Default Value: 80
+             80-4096 for all other supported adapters
+Default Value: 256
     This value is the number of receive descriptors allocated by the driver. 
     Increasing this value allows the driver to buffer more incoming packets. 
     Each descriptor is 16 bytes.  A receive buffer is also allocated for each
@@ -149,6 +151,9 @@ Default Value: 80
 
     NOTE: MTU designates the frame size. It only needs to be set for Jumbo 
           Frames.
+    NOTE: Depending on the available system resources, the request for a
+    higher number of receive descriptors may be denied.  In this case,
+    use a lower number.
 
 RxIntDelay
 Valid Range: 0-65535 (0=off)
@@ -168,11 +173,11 @@ Default Value: 0
              restoring the network connection. To eliminate the potential for
              the hang ensure that RxIntDelay is set to 0.
 
-RxAbsIntDelay (82540, 82545, and 82546-based adapters only)
+RxAbsIntDelay (82540, 82545 and later adapters only)
 Valid Range: 0-65535 (0=off)
 Default Value: 128
     This value, in units of 1.024 microseconds, limits the delay in which a 
-    transmit interrupt is generated. Useful only if RxIntDelay is non-zero, 
+    receive interrupt is generated. Useful only if RxIntDelay is non-zero, 
     this value ensures that an interrupt is generated after the initial 
     packet is received within the set amount of time.  Proper tuning,
     along with RxIntDelay, may improve traffic throughput in specific network
@@ -188,12 +193,16 @@ Default Value: 0 (auto-negotiate at all supported speeds)
 
 TxDescriptors
 Valid Range: 80-256 for 82542 and 82543-based adapters
-             80-4096 for 82540, 82544, 82545, and 82546-based adapters
+             80-4096 for all other supported adapters
 Default Value: 256
     This value is the number of transmit descriptors allocated by the driver.
     Increasing this value allows the driver to queue more transmits. Each 
     descriptor is 16 bytes.
 
+    NOTE: Depending on the available system resources, the request for a
+    higher number of transmit descriptors may be denied.  In this case,
+    use a lower number.
+
 TxIntDelay
 Valid Range: 0-65535 (0=off)
 Default Value: 64
@@ -203,7 +212,7 @@ Default Value: 64
     system is reporting dropped transmits, this value may be set too high
     causing the driver to run out of available transmit descriptors.
 
-TxAbsIntDelay (82540, 82545, and 82546-based adapters only)
+TxAbsIntDelay (82540, 82545 and later adapters only)
 Valid Range: 0-65535 (0=off)
 Default Value: 64
     This value, in units of 1.024 microseconds, limits the delay in which a 
@@ -219,7 +228,6 @@ Default Value: 1
     A value of '1' indicates that the driver should enable IP checksum
     offload for received packets (both UDP and TCP) to the adapter hardware.
 
-
 Speed and Duplex Configuration
 ==============================
 
@@ -251,6 +259,10 @@ Bit            7      6      5       4       3      2      1       0
 Speed (Mbps)   N/A    N/A    1000    N/A     100    100    10      10
 Duplex                       Full            Full   Half   Full    Half
 
+For example to limit the negotiated speed/duplex on the interface to 10 Mbps 
+Half or Full duplex, set AutoNeg to 0x02: 
+    insmod e1000 AutoNeg=0x02
+
 Note that setting AutoNeg does not guarantee that the board will link at the 
 highest specified speed or duplex mode, but the board will link at the 
 highest possible speed/duplex of the link partner IF the link partner is also
@@ -261,6 +273,38 @@ adapter MUST be forced to the same speed/duplex.
 Additional Configurations
 =========================
 
+  Configuring the Driver on Different Distributions
+  -------------------------------------------------
+
+  Configuring a network driver to load properly when the system is started is
+  distribution dependent. Typically, the configuration process involves adding
+  an alias line to /etc/modules.conf as well as editing other system startup 
+  scripts and/or configuration files. Many popular Linux distributions ship 
+  with tools to make these changes for you. To learn the proper way to 
+  configure a network device for your system, refer to your distribution 
+  documentation. If during this process you are asked for the driver or module 
+  name, the name for the Linux Base Driver for the Intel PRO/1000 Family of 
+  Adapters is e1000.
+
+  As an example, if you install the e1000 driver for two PRO/1000 adapters 
+  (eth0 and eth1) and set the speed and duplex to 10full and 100half, add the 
+  following to modules.conf:
+
+       alias eth0 e1000
+       alias eth1 e1000
+       options e1000 Speed=10,100 Duplex=2,1
+
+  Viewing Link Messages
+  ---------------------
+
+  Link messages will not be displayed to the console if the distribution is 
+  restricting system messages. In order to see network driver link messages on 
+  your console, set dmesg to eight by entering the following:
+
+       dmesg -n 8
+
+  NOTE: This setting is not saved across reboots.
+
   Jumbo Frames
   ------------
 
@@ -278,6 +322,51 @@ Additional Configurations
   10 or 100 Mbps may result in poor performance or loss of link.
 
 
+  NOTE: MTU designates the frame size. To enable Jumbo Frames, increase the
+  MTU size on the interface beyond 1500.
+
+  Ethtool
+  -------
+
+  The driver utilizes the ethtool interface for driver configuration and
+  diagnostics, as well as displaying statistical information.  Ethtool
+  version 1.6 or later is required for this functionality.
+
+  The latest release of ethtool can be found from
+  http://sf.net/projects/gkernel.  After ethtool is installed,
+  ethtool-copy.h must be copied and renamed to ethtool.h in your kernel
+  source tree at <linux_kernel_src>/include/linux.  Backup the original
+  ethtool.h as needed before copying.  The driver then must be recompiled
+  in order to take advantage of the latest ethtool features.
+
+  NOTE: Ethtool 1.6 only supports a limited set of ethtool options. Support 
+  for a more complete ethtool feature set can be enabled by upgrading 
+  ethtool to ethtool-1.8.1. 
+
+  Enabling Wake on LAN* (WoL)
+  ---------------------------
+
+  WoL is configured through the Ethtool* utility. Ethtool is included with
+  all versions of Red Hat after Red Hat 7.2. For other Linux distributions, 
+  download and install Ethtool from the following website: 
+  http://sourceforge.net/projects/gkernel.
+
+  For instructions on enabling WoL with Ethtool, refer to the website listed 
+  above.
+
+  WoL will be enabled on the system during the next shut down or reboot. 
+  For this driver version, in order to enable WoL, the e1000 driver must be 
+  loaded when shutting down or rebooting the system.
+
+  NAPI
+  ----
+
+  NAPI (Rx polling mode) is supported in the e1000 driver. NAPI is enabled
+  or disabled based on the configuration of the kernel. 
+
+  See www.cyberus.ca/~hadi/usenix-paper.tgz for more information on NAPI.
+
+
 Known Issues
 ============
 
@@ -285,9 +374,9 @@ Known Issues
   -------------------------------
 
   Memory allocation failures have been observed on Linux systems with 64 MB 
-  of RAM or less that are running Jumbo Frames. If you are using Jumbo 
-  Frames, your system may require more than the advertised minimum 
-  requirement of 64 MB of system memory.
+  of RAM or less that are running Jumbo Frames. If you are using Jumbo Frames,
+  your system may require more than the advertised minimum requirement of 64 MB
+  of system memory.
 
 
 Support
index 993090c..c62d588 100644 (file)
@@ -1,14 +1,14 @@
 Linux* Base Driver for the Intel(R) PRO/10GbE Family of Adapters
 ================================================================
 
-January 06, 2003
+September 13, 2004
 
 
 Contents
 ========
 
 - In This Release
-- Supported Adapters
+- Identifying Your Adapter
 - Command Line Parameters
 - Improving Performance
 - Support
@@ -18,36 +18,23 @@ In This Release
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/10GbE Family 
-of Adapters, version 1.0.x. This driver is intended for 2.4.x kernels; it is 
-known to build properly on 2.4.x kernels through 2.4.18. Intel focused 
-testing on Intel architectures running kernels 2.4.18. This driver includes 
-support for Itanium(TM)-based systems.
+of Adapters, version 1.0.x.  This driver includes support for Itanium(TM)2 and
+EM64T systems.
 
 For questions related to hardware requirements, refer to the documentation 
 supplied with your Intel PRO/10GbE adapter. All hardware requirements listed 
 apply to use with Linux.
 
-
-Supported Adapters
-==================
-
-The following Intel network adapters are compatible with the drivers in this 
-release:
-
-   Controller  Adapter Name                           Board IDs
-   ----------  ------------                           ---------
-
-   82597EX     Intel(R) PRO/10GbE LR Server Adapter   A82505-xxx
-
+Identifying Your Adapter
+========================
 
 To verify your Intel adapter is supported, find the board ID number on the 
 adapter. Look for a label that has a barcode and a number in the format  
-A12345-001. Match this to the list of numbers above.
+A12345-001. 
 
-For more information on how to identify your adapter, go to the Adapter & 
-Driver ID Guide at:
+Use the above information and the Adapter & Driver ID Guide at:
 
-    http://support.intel.com/support/network/adapter/pro100/21397.htm
+  http://support.intel.com/support/network/adapter/pro100/21397.htm
 
 For the latest Intel network drivers for Linux, go to:
 
@@ -72,8 +59,9 @@ loads the ixgb driver with 80 TX resources for the first adapter and 128 TX
 resources for the second adapter.
 
 The default value for each parameter is generally the recommended setting,
-unless otherwise noted.
-
+unless otherwise noted. Also, if the driver is statically built into the
+kernel, the driver is loaded with the default values for all the parameters.
+Ethtool can be used to change some of the parameters at runtime.
 
 FlowControl
 Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx)
@@ -125,7 +113,6 @@ Default Value: 1
     offload for transmitted packets (both UDP and TCP) to the adapter 
     hardware.
 
-
 Improving Performance
 =====================
 
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
index 6cad46e..c025a45 100644 (file)
@@ -54,6 +54,20 @@ then the system has crashed so hard (eg. hardware-wise) that either it
 cannot even accept NMI interrupts, or the crash has made the kernel
 unable to print messages.
 
+Be aware that when using local APIC, the frequency of NMI interrupts
+it generates, depends on the system load. The local APIC NMI watchdog,
+lacking a better source, uses the "cycles unhalted" event. As you may
+guess it doesn't tick when the CPU is in the halted state (which happens
+when the system is idle), but if your system locks up on anything but the
+"hlt" processor instruction, the watchdog will trigger very soon as the
+"cycles unhalted" event will happen every clock tick. If it locks up on
+"hlt", then you are out of luck -- the event will not happen at all and the
+watchdog won't trigger. This is a shortcoming of the local APIC watchdog
+-- unfortunately there is no "clock ticks" event that would work all the
+time. The I/O APIC watchdog is driven externally and has no such shortcoming.  
+But its NMI frequency is much higher, resulting in a more significant hit
+to the overall system performance.
+
 NOTE: starting with 2.4.2-ac18 the NMI-oopser is disabled by default,
 you have to enable it with a boot time parameter.  Prior to 2.4.2-ac18
 the NMI-oopser is enabled unconditionally on x86 SMP boxes.
index 08b9f55..dd3cadd 100644 (file)
@@ -35,8 +35,8 @@ CR31 (TR 7)                   Temporary register, used in various places
 SR0                            temporary space register
 SR4-SR7                        set to 0
 SR1                            temporary space register
-SR2                            unused
-SR3                            used for userspace accesses (current process)*
+SR2                            kernel should not clobber this
+SR3                            used for userspace accesses (current process)
 
        Space Registers (user mode)
 
@@ -78,13 +78,8 @@ Shadow Registers             used by interruption handler code
 TOC enable bit                 1
 
 =========================================================================
-Info from John Marvin:
-
-From: "John Marvin" <jsm@udlkern.fc.hp.com>
-To: randolf@tausq.org
-Subject: Re: parisc asm questions
-
-[...]
+Register usage notes, originally from John Marvin, with some additional
+notes from Randolph Chung.
 
 For the general registers:
 
@@ -111,9 +106,10 @@ that you should be aware of:
        don't care about the values that were passed in anymore.
 
     r28,r29: are ret0 and ret1. They are what you pass return values
-       in. r28 is the primary return. I'm not sure I remember
-       under what circumstances stuff is returned in r29 (millicode
-       perhaps).
+       in. r28 is the primary return. When returning small structures
+       r29 may also be used to pass data back to the caller.
+
+    r30: stack pointer
 
     r31: the ble instruction puts the return pointer in here.
 
@@ -123,6 +119,3 @@ r3-r18,r27,r30 need to be saved and restored. r3-r18 are just
     used to make references to global variables easier. r30 is
     the stack pointer.
 
-John
-
-
index 483d2a5..008ac7d 100644 (file)
@@ -36,8 +36,8 @@ system the associated daemon will exit gracefully.
   apmd:   http://worldvisions.ca/~apenwarr/apmd/
   acpid:  http://acpid.sf.net/
 
-Driver Interface
-----------------
+Driver Interface -- OBSOLETE, DO NOT USE!
+----------------*************************
 If you are writing a new driver or maintaining an old driver, it
 should include power management support.  Without power management
 support, a single driver may prevent a system with power management
@@ -262,8 +262,8 @@ Q: Who do I contact for additional information about
 
 ACPI Development mailing list: acpi-devel@lists.sourceforge.net
 
-System Interface
-----------------
+System Interface -- OBSOLETE, DO NOT USE!
+----------------*************************
 If you are providing new power management support to Linux (ie.
 adding support for something like APM or ACPI), you should
 communicate with drivers through the existing generic power
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.
+
+
index 1f937c3..7c25584 100644 (file)
@@ -5,115 +5,66 @@ Contents:
 
        1) Overview
        2) Kernel Command Line Parameters
-       3) Using "rdev -r" With New Kernels
+       3) Using "rdev -r"
        4) An Example of Creating a Compressed RAM Disk 
 
 
 1) Overview
 -----------
 
-As of kernel v1.3.48, the RAM disk driver was substantially changed.
+The RAM disk driver is a way to use main system memory as a block device.  It
+is required for initrd, an initial filesystem used if you need to load modules
+in order to access the root filesystem (see Documentation/initrd.txt).  It can
+also be used for a temporary filesystem for crypto work, since the contents
+are erased on reboot.
 
-The older versions would grab a chunk of memory off the top before
-handing the remainder to the kernel at boot time. Thus a size parameter
-had to be specified via "ramdisk=1440" or "rdev -r /dev/fd0 1440" so
-that the driver knew how much memory to grab.
+The RAM disk dynamically grows as more space is required. It does this by using
+RAM from the buffer cache. The driver marks the buffers it is using as dirty
+so that the VM subsystem does not try to reclaim them later.
 
-Now the RAM disk dynamically grows as more space is required. It does
-this by using RAM from the buffer cache. The driver marks the buffers
-it is using with a new "BH_Protected" flag so that the kernel does 
-not try to reuse them later. This means that the old size parameter
-is no longer used, new command line parameters exist, and the behavior
-of the "rdev -r" or "ramsize" (usually a symbolic link to "rdev")
-command has changed.
+Also, the RAM disk supports up to 16 RAM disks out of the box, and can
+be reconfigured to support up to 255 RAM disks - change "#define NUM_RAMDISKS"
+in drivers/block/rd.c.  To use RAM disk support with your system, run
+'./MAKEDEV ram' from the /dev directory.  RAM disks are all major number 1, and
+start with minor number 0 for /dev/ram0, etc.  If used, modern kernels use
+/dev/ram0 for an initrd.
 
-Also, the new RAM disk supports up to 16 RAM disks out of the box, and can
-be reconfigured in rd.c to support up to 255 RAM disks.  To use multiple
-RAM disk support with your system, run 'mknod /dev/ramX b 1 X' and chmod
-(to change its permissions) it to your liking.  The default /dev/ram(disk)
-uses minor #1, so start with ram2 and go from there.
-
-The old "ramdisk=<ram_size>" has been changed to "ramdisk_size=<ram_size>"
-to make it clearer.  The original "ramdisk=<ram_size>" has been kept around
-for compatibility reasons, but it will probably be removed in 2.1.x.
+The old "ramdisk=<ram_size>" has been changed to "ramdisk_size=<ram_size>" to
+make it clearer.  The original "ramdisk=<ram_size>" has been kept around for
+compatibility reasons, but it may be removed in the future.
 
 The new RAM disk also has the ability to load compressed RAM disk images,
 allowing one to squeeze more programs onto an average installation or 
 rescue floppy disk.
 
-Notes: You may have "/dev/ram" or "/dev/ramdisk" or both. They are
-equivalent from the standpoint of this document. Also, the new RAM disk
-is a config option. When running "make config", make sure you enable
-RAM disk support for the kernel with which you intend to use the RAM disk.
-
 
 2) Kernel Command Line Parameters
 ---------------------------------
 
-       ramdisk_start=NNN
-       =================
-
-To allow a kernel image to reside on a floppy disk along with a compressed
-RAM disk image, the "ramdisk_start=<offset>" command was added. The kernel
-can't be included into the compressed RAM disk filesystem image, because
-it needs to be stored starting at block zero so that the BIOS can load the 
-boot sector and then the kernel can bootstrap itself to get going.
-
-Note: If you are using an uncompressed RAM disk image, then the kernel can
-be a part of the filesystem image that is being loaded into the RAM disk,
-and the floppy can be booted with LILO, or the two can be separate as
-is done for the compressed images.
-
-If you are using a two-disk boot/root setup (kernel on #1, RAM disk image
-on #2) then the RAM disk would start at block zero, and an offset of
-zero would be used. Since this is the default value, you would not need
-to actually use the command at all.
-
-If instead, you have a "zImage" of about 350 kB, and a "fs_image.gz" of
-say about 1 MB, and you want them both on the same disk, then you
-would use an offset. If you stored the "fs_image.gz" onto the floppy
-starting at an offset of 400 kB, you would use "ramdisk_start=400".
-
-
-       load_ramdisk=N
+       ramdisk_size=N
        ==============
 
-This parameter tells the kernel whether it is to try to load a
-RAM disk image or not. Specifying "load_ramdisk=1" will tell the
-kernel to load a floppy into the RAM disk. The default value is
-zero, meaning that the kernel should not try to load a RAM disk.
-
+This parameter tells the RAM disk driver to set up RAM disks of N k size.  The
+default is 4096 (4 MB) (8192 (8 MB) on S390).
 
-       prompt_ramdisk=N
-       ================
+       ramdisk_blocksize=N
+       ===================
 
-This parameter tells the kernel whether or not to give you a prompt
-asking you to insert the floppy containing the RAM disk image. In
-a single floppy configuration the RAM disk image is on the same floppy
-as the kernel that just finished loading/booting and so a prompt
-is not needed. In this case one can use "prompt_ramdisk=0". In a
-two floppy configuration, you will need the chance to switch disks,
-and thus "prompt_ramdisk=1" can be used. Since this is the default 
-value, it doesn't really need to be specified.
+This parameter tells the RAM disk driver how many bytes to use per block.  The
+default is 512.
 
-       ramdisk_size=N
-       ==============
-
-This parameter tells the RAM disk driver to set up RAM disks of N k size.  The
-default is 4096 (4 MB). 
 
-3) Using "rdev -r" With New Kernels
------------------------------------
+3) Using "rdev -r"
+------------------
 
-The usage of the word (two bytes) that "rdev -r" sets in the kernel image
-has changed. The low 11 bits (0 -> 10) specify an offset (in 1 k blocks) 
-of up to 2 MB (2^11) of where to find the RAM disk (this used to be the 
-size). Bit 14 indicates that a RAM disk is to be loaded, and bit 15
-indicates whether a prompt/wait sequence is to be given before trying
-to read the RAM disk. Since the RAM disk dynamically grows as data is
-being written into it, a size field is no longer required. Bits 11
-to 13 are not currently used and may as well be zero. These numbers
-are no magical secrets, as seen below:
+The usage of the word (two bytes) that "rdev -r" sets in the kernel image is
+as follows. The low 11 bits (0 -> 10) specify an offset (in 1 k blocks) of up
+to 2 MB (2^11) of where to find the RAM disk (this used to be the size). Bit
+14 indicates that a RAM disk is to be loaded, and bit 15 indicates whether a
+prompt/wait sequence is to be given before trying to read the RAM disk. Since
+the RAM disk dynamically grows as data is being written into it, a size field
+is not required. Bits 11 to 13 are not currently used and may as well be zero.
+These numbers are no magical secrets, as seen below:
 
 ./arch/i386/kernel/setup.c:#define RAMDISK_IMAGE_START_MASK     0x07FF
 ./arch/i386/kernel/setup.c:#define RAMDISK_PROMPT_FLAG          0x8000
@@ -152,10 +103,10 @@ Since the default start = 0 and the default prompt = 1, you could use:
 To create a RAM disk image, you will need a spare block device to
 construct it on. This can be the RAM disk device itself, or an
 unused disk partition (such as an unmounted swap partition). For this 
-example, we will use the RAM disk device, "/dev/ram".
+example, we will use the RAM disk device, "/dev/ram0".
 
 Note: This technique should not be done on a machine with less than 8 MB
-of RAM. If using a spare disk partition instead of /dev/ram, then this
+of RAM. If using a spare disk partition instead of /dev/ram0, then this
 restriction does not apply.
 
 a) Decide on the RAM disk size that you want. Say 2 MB for this example.
@@ -164,11 +115,11 @@ a) Decide on the RAM disk size that you want. Say 2 MB for this example.
    area (esp. for disks) so that maximal compression is achieved for
    the unused blocks of the image that you are about to create.
 
-       dd if=/dev/zero of=/dev/ram bs=1k count=2048
+       dd if=/dev/zero of=/dev/ram0 bs=1k count=2048
 
 b) Make a filesystem on it. Say ext2fs for this example.
 
-       mke2fs -vm0 /dev/ram 2048
+       mke2fs -vm0 /dev/ram0 2048
 
 c) Mount it, copy the files you want to it (eg: /etc/* /dev/* ...)
    and unmount it again.
@@ -177,7 +128,7 @@ d) Compress the contents of the RAM disk. The level of compression
    will be approximately 50% of the space used by the files. Unused
    space on the RAM disk will compress to almost nothing.
 
-       dd if=/dev/ram bs=1k count=2048 | gzip -v9 > /tmp/ram_image.gz
+       dd if=/dev/ram0 bs=1k count=2048 | gzip -v9 > /tmp/ram_image.gz
 
 e) Put the kernel onto the floppy
 
@@ -203,4 +154,14 @@ That is it. You now have your boot/root compressed RAM disk floppy. Some
 users may wish to combine steps (d) and (f) by using a pipe.
 
 --------------------------------------------------------------------------
-                                               Paul Gortmaker 12/95    
+                                               Paul Gortmaker 12/95
+
+Changelog:
+----------
+
+10-22-04 :     Updated to reflect changes in command line options, remove
+               obsolete references, general cleanup.
+               James Nelson (james4765@gmail.com)
+
+
+12-95 :                Original Document
index f9345cd..a106780 100644 (file)
@@ -20,8 +20,27 @@ or installing it into kernels which do not have the driver configured
 into them.  Installations instructions for the external module
 are in the included README and HW_INSTALL files.
 
-RocketPort ISA and RocketModem II PCI boards are also supported by this
-driver, but must use the external module driver for configuration reasons.  
+RocketPort ISA and RocketModem II PCI boards currently are only supported by
+this driver in module form.
+
+The RocketPort ISA board requires I/O ports to be configured by the DIP
+switches on the board.  See the section "ISA Rocketport Boards" below for
+information on how to set the DIP switches.
+
+You pass the I/O port to the driver using the following module parameters:
+
+board1 :       I/O port for the first ISA board
+board2 :       I/O port for the second ISA board
+board3 :       I/O port for the third ISA board
+board4 :       I/O port for the fourth ISA board
+
+There is a set of utilities and scripts provided with the external driver
+( downloadable from http://www.comtrol.com ) that ease the configuration and
+setup of the ISA cards.
+
+The RocketModem II PCI boards require firmware to be loaded into the card
+before it will function.  The driver has only been tested as a module for this
+board.
 
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
@@ -55,12 +74,95 @@ create the RocketPort/RocketModem device names, use the command
 >mknod /dev/ttyR1 c 46 1
 >mknod /dev/ttyR2 c 46 2  
 
-The Linux script MAKEDEV will create the first 16 ttyRx device names (nodes) for you:
+The Linux script MAKEDEV will create the first 16 ttyRx device names (nodes)
+for you:
 
 >/dev/MAKEDEV ttyR
 
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
+ISA Rocketport Boards
+---------------------
+
+You must assign and configure the I/O addresses used by the ISA Rocketport
+card before installing and using it.  This is done by setting a set of DIP
+switches on the Rocketport board.
+
+
+SETTING THE I/O ADDRESS
+-----------------------
+
+Before installing RocketPort(R) or RocketPort RA boards, you must find
+a range of I/O addresses for it to use. The first RocketPort card
+requires a 68-byte contiguous block of I/O addresses, starting at one
+of the following: 0x100h, 0x140h, 0x180h, 0x200h, 0x240h, 0x280h,
+0x300h, 0x340h, 0x380h.  This I/O address must be reflected in the DIP
+switiches of *all* of the Rocketport cards.
+
+The second, third, and fourth RocketPort cards require a 64-byte
+contiguous block of I/O addresses, starting at one of the following
+I/O addresses: 0x100h, 0x140h, 0x180h, 0x1C0h, 0x200h, 0x240h, 0x280h,
+0x2C0h, 0x300h, 0x340h, 0x380h, 0x3C0h.  The I/O address used by the
+second, third, and fourth Rocketport cards (if present) are set via
+software control.  The DIP switch settings for the I/O address must be
+set to the value of the first Rocketport cards.
+
+In order to destinguish each of the card from the others, each card
+must have a unique board ID set on the dip switches.  The first
+Rocketport board must be set with the DIP switches corresponding to
+the first board, the second board must be set with the DIP switches
+corresponding to the second board, etc.  IMPORTANT: The board ID is
+the only place where the DIP switch settings should differ between the
+various Rocketport boards in a system.
+
+The I/O address range used by any of the RocketPort cards must not
+conflict with any other cards in the system, including other
+RocketPort cards.  Below, you will find a list of commonly used I/O
+address ranges which may be in use by other devices in your system.
+On a Linux system, "cat /proc/ioports" will also be helpful in
+identifying what I/O addresses are being used by devics on your
+system.
+
+Remember, the FIRST RocketPort uses 68 I/O addresses.  So, if you set it
+for 0x100, it will occupy 0x100 to 0x143.  This would mean that you
+CAN NOT set the second, third or fourth board for address 0x140 since
+the first 4 bytes of that range are used by the first board.  You would
+need to set the second, third, or fourth board to one of the next available
+blocks such as 0x180.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+RocketPort and RocketPort RA SW1 Settings:
+
+          +-------------------------------+
+          | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
+          +-------+-------+---------------+
+          | Unused| Card  | I/O Port Block|
+          +-------------------------------+
+
+DIP Switches                             DIP Switches
+7    8                                   6    5
+===================                      ===================
+On   On   UNUSED, MUST BE ON.            On   On   First Card    <==== Default
+                                         On   Off  Second Card
+                                         Off  On   Third Card
+                                         Off  Off  Fourth Card
+
+DIP Switches         I/O Address Range
+4    3    2    1     Used by the First Card
+=====================================
+On   Off  On   Off   100-143
+On   Off  Off  On    140-183
+On   Off  Off  Off   180-1C3       <==== Default
+Off  On   On   Off   200-243
+Off  On   Off  On    240-283
+Off  On   Off  Off   280-2C3
+Off  Off  On   Off   300-343
+Off  Off  Off  On    340-383
+Off  Off  Off  Off   380-3C3
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
 REPORTING BUGS
 --------------
 
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.
+
index 692cc26..2d1cd93 100644 (file)
@@ -78,6 +78,23 @@ Example:
 
 > echo "-" > /proc/s390dbf/dasd/level
 
+It is also possible to deactivate the debug feature globally for every
+debug log. You can change the behavior using  2 sysctl parameters in
+/proc/sys/s390dbf:
+There are currently 2 possible triggers, which stop the  debug feature
+globally. The first possbility is to use the "debug_active" sysctl. If
+set to 1 the debug feature is running. If "debug_active" is set to 0 the
+debug feature is turned off.
+The second trigger which stops the debug feature is an kernel oops.
+That prevents the debug feature from overwriting debug information that
+happened before the oops. After an oops you can reactivate the debug feature
+by piping 1 to /proc/sys/s390dbf/debug_active. Nevertheless, its not
+suggested to use an oopsed kernel in an production environment.
+If you want to disallow the deactivation of the debug feature, you can use
+the "debug_stoppable" sysctl. If you set "debug_stoppable" to 0 the debug
+feature cannot be stopped. If the debug feature is already stopped, it
+will stay deactivated.
+
 Kernel Interfaces:
 ------------------
 
@@ -115,6 +132,17 @@ Parameter:     id:        handle for debug log
 Return Value:  none 
 
 Description:   Sets new actual debug level if new_level is valid. 
+
+---------------------------------------------------------------------------
++void debug_stop_all(void);
+
+Parameter:     none
+
+Return Value:  none
+
+Description:   stops the debug feature if stopping is allowed. Currently
+               used in case of a kernel oops.
+
 ---------------------------------------------------------------------------
 debug_entry_t* debug_event (debug_info_t* id, int level, void* data, 
                             int length);
@@ -271,12 +299,12 @@ Examples
  * hex_ascii- + raw-view Example
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <asm/debug.h>
 
 static debug_info_t* debug_info;
 
-int init_module(void)
+static int init(void)
 {
     /* register 4 debug areas with one page each and 4 byte data field */
 
@@ -291,23 +319,26 @@ int init_module(void)
     return 0;
 }
 
-void cleanup_module(void)
+static void cleanup(void)
 {
     debug_unregister (debug_info);
 }
 
+module_init(init);
+module_exit(cleanup);
+
 ---------------------------------------------------------------------------
 
 /*
  * sprintf-view Example
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <asm/debug.h>
 
 static debug_info_t* debug_info;
 
-int init_module(void)
+static int init(void)
 {
     /* register 4 debug areas with one page each and data field for */
     /* format string pointer + 2 varargs (= 3 * sizeof(long))       */
@@ -321,11 +352,14 @@ int init_module(void)
     return 0;
 }
 
-void cleanup_module(void)
+static void cleanup(void)
 {
     debug_unregister (debug_info);
 }
 
+module_init(init);
+module_exit(cleanup);
+
 
 
 ProcFS Interface
@@ -377,6 +411,15 @@ Examples:
 2. Flush all debug areas:
 > echo "-" > /proc/s390dbf/dasd/flush
 
+Stooping the debug feature
+--------------------------
+Example:
+
+1. Check if stopping is allowed
+> cat /proc/sys/s390dbf/debug_stoppable
+2. Stop debug feature
+> echo 0 > /proc/sys/s390dbf/debug_active
+
 lcrash Interface
 ----------------
 It is planned that the dump analysis tool lcrash gets an additional command
index 431e398..79a9aed 100644 (file)
@@ -1,3 +1,27 @@
+Release Date   : Thu Dec  9 19:02:14 EST 2004 - Sreenivas Bagalkote <sreenib@lsil.com>
+
+Current Version        : 2.20.4.1 (scsi module), 2.20.2.3 (cmm module)
+Older Version  : 2.20.4.1 (scsi module), 2.20.2.2 (cmm module)
+
+i.     Fix a bug in kioc's dma buffer deallocation
+
+Release Date   : Thu Nov  4 18:24:56 EST 2004 - Sreenivas Bagalkote <sreenib@lsil.com>
+
+Current Version        : 2.20.4.1 (scsi module), 2.20.2.2 (cmm module)
+Older Version  : 2.20.4.0 (scsi module), 2.20.2.1 (cmm module)
+
+i.     Handle IOCTL cmd timeouts more properly.
+
+ii.    pci_dma_sync_{sg,single}_for_cpu was introduced into megaraid_mbox
+       incorrectly (instead of _for_device). Changed to appropriate
+       pci_dma_sync_{sg,single}_for_device.
+
+Release Date   : Wed Oct 06 11:15:29 EDT 2004 - Sreenivas Bagalkote <sreenib@lsil.com>
+Current Version        : 2.20.4.0 (scsi module), 2.20.2.1 (cmm module)
+Older Version  : 2.20.4.0 (scsi module), 2.20.2.0 (cmm module)
+
+i.     Remove CONFIG_COMPAT around register_ioctl32_conversion
+
 Release Date   : Mon Sep 27 22:15:07 EDT 2004 - Atul Mukker <atulm@lsil.com>
 Current Version        : 2.20.4.0 (scsi module), 2.20.2.0 (cmm module)
 Older Version  : 2.20.3.1 (scsi module), 2.20.2.0 (cmm module)
index f13415a..af9abe2 100644 (file)
@@ -4,7 +4,9 @@ Written by Gerard Roudier <groudier@free.fr>
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
-Decembre 28 2000
+Updated by Matthew Wilcox <matthew@wil.cx>
+
+2004-10-09
 ===============================================================================
 
 1.  Introduction
@@ -29,26 +31,20 @@ Decembre 28 2000
 10. Boot setup commands
       10.1 Syntax
       10.2 Available arguments
-             10.2.1  Master parity checking
-             10.2.2  Scsi parity checking
-             10.2.3  Default number of tagged commands
-             10.2.4  Default synchronous period factor
-             10.2.5  Verbosity level
-             10.2.6  Debug mode
-             10.2.7  Burst max
-             10.2.8  LED support
-             10.2.9  Max wide
-             10.2.10 Differential mode
-             10.2.11 IRQ mode
-             10.2.12 Reverse probe
-             10.2.13 Fix up PCI configuration space
-             10.2.14 Serial NVRAM
-             10.2.15 Check SCSI BUS 
-             10.2.16 Exclude a host from being attached
-             10.2.17 Suggest a default SCSI id for hosts
-      10.3 PCI configuration fix-up boot option
-      10.4 Serial NVRAM support boot option
-      10.5 SCSI BUS checking boot option
+             10.2.1  Default number of tagged commands
+             10.2.2  Burst max
+             10.2.3  LED support
+             10.2.4  Differential mode
+             10.2.5  IRQ mode
+             10.2.6  Check SCSI BUS 
+             10.2.7  Suggest a default SCSI id for hosts
+             10.2.8  Verbosity level
+             10.2.9  Debug mode
+             10.2.10 Settle delay
+             10.2.11 Serial NVRAM
+             10.2.12 Exclude a host from being attached
+      10.3 Converting from old options
+      10.4 SCSI BUS checking boot option
 11. SCSI problem troubleshooting
       15.1 Problem tracking
       15.2 Understanding hardware error reports
@@ -94,6 +90,9 @@ The history of this driver can be summerized as follows:
       Write a glue code for Linux.
           Gerard Roudier
 
+2004: Remove FreeBSD compatibility code.  Remove support for versions of
+      Linux before 2.6.  Start using Linux facilities.
+
 This README file addresses the Linux version of the driver. Under FreeBSD, 
 the driver documentation is the sym.8 man page.
 
@@ -279,11 +278,10 @@ setting verbose level to zero, as follow:
 6. Parity checking
 
 The driver supports SCSI parity checking and PCI bus master parity
-checking. These features must be enabled in order to ensure safe data
-transfers. However, some flawed devices or mother boards will have
-problems with parity. You can disable either PCI parity or SCSI parity 
-checking by entering appropriate options from the boot command line.
-(See 10: Boot setup commands).
+checking.  These features must be enabled in order to ensure safe
+data transfers.  Some flawed devices or mother boards may have problems
+with parity.  The options to defeat parity checking have been removed
+from the driver.
 
 7. Profiling information
 
@@ -428,77 +426,90 @@ Synchronous transfers frequency       (default answer: 80)
 
 10.1 Syntax
 
-Setup commands can be passed to the driver either at boot time or as a 
-string variable using 'insmod'.
-
-A boot setup command for this driver begins with the driver name "sym53c8xx=".
-The kernel syntax parser then expects an optionnal list of integers separated 
-with comma followed by an optional list of  comma-separated strings.
+Setup commands can be passed to the driver either at boot time or as
+parameters to modprobe, as described in Documentation/kernel-parameters.txt
 
 Example of boot setup command under lilo prompt:
 
-lilo: linux root=/dev/sda2 sym53c8xx=tags:4,sync:10,debug:0x200
+lilo: linux root=/dev/sda2 sym53c8xx.cmd_per_lun=4 sym53c8xx.sync=10 sym53c8xx.debug=0x200
 
 - enable tagged commands, up to 4 tagged commands queued.
 - set synchronous negotiation speed to 10 Mega-transfers / second.
 - set DEBUG_NEGO flag.
 
-Since comma seems not to be allowed when defining a string variable using  
-'insmod', the driver also accepts <space> as option separator. 
-The following command will install driver module with the same options as 
-above.
-
-    insmod sym53c8xx.o sym53c8xx="tags:4 sync:10 debug:0x200"
+The following command will install the driver module with the same
+options as above.
 
-The integer list of arguments is discarded by the driver. 
-
-Each string argument must be specified as "keyword:value". Only lower-case 
-characters and digits are allowed.
+    modprobe sym53c8xx cmd_per_lun=4 sync=10 debug=0x200"
 
 10.2 Available arguments
 
-10.2.1  Master parity checking
-        mpar:y     enabled
-        mpar:n     disabled
-
-10.2.2  Scsi parity checking
-        spar:y     enabled
-        spar:n     disabled
-
-10.2.3  Default number of tagged commands
-        tags:0     (or tags:1 ) tagged command queuing disabled
-        tags:#tags (#tags  > 1) tagged command queuing enabled
+10.2.1  Default number of tagged commands
+        cmd_per_lun=0 (or cmd_per_lun=1) tagged command queuing disabled
+        cmd_per_lun=#tags (#tags > 1) tagged command queuing enabled
   #tags will be truncated to the max queued commands configuration parameter.
-  This option also allows to specify a command queue depth for each device 
-  that support tagged command queueing.
+
+10.2.2  Detailed control of tagged commands
+  This option allows you to specify a command queue depth for each device 
+  that supports tagged command queueing.
   Example:
-      sym53c8xx=tags:10/t2t3q16-t5q24/t1u2q32
-               will set devices queue depth as follow:
+      tag_ctrl=10/t2t3q16-t5q24/t1u2q32
+  will set devices queue depth as follow:
       - controller #0 target #2 and target #3                  -> 16 commands,
       - controller #0 target #5                                -> 24 commands,
       - controller #1 target #1 logical unit #2                -> 32 commands,
       - all other logical units (all targets, all controllers) -> 10 commands.
 
-10.2.4  Default synchronous period factor
-        sync:255     disabled (asynchronous transfer mode)
-        sync:#factor
-  #factor =  9     Ultra-3 SCSI 80 Mega-transfers / second (Wide only)
-  #factor = 10     Ultra-2 SCSI 40 Mega-transfers / second
-  #factor = 11     Ultra-2 SCSI 33 Mega-transfers / second
-  #factor < 25     Ultra   SCSI 20 Mega-transfers / second
-  #factor < 50     Fast    SCSI-2
-
-  In all cases, the driver will use the minimum transfer period supported by 
-  controllers according to SYM53C8XX chip type.
-
-10.2.5  Verbosity level
-        verb:0     minimal
-        verb:1     normal
-        verb:2     too much
-
-10.2.6 Debug mode
-        debug:0         clear debug flags
-        debug:#x   set debug flags
+10.2.3 Burst max
+        burst=0    burst disabled
+        burst=255  get burst length from initial IO register settings.
+        burst=#x   burst enabled (1<<#x burst transfers max)
+  #x is an integer value which is log base 2 of the burst transfers max.
+  By default the driver uses the maximum value supported by the chip.
+
+10.2.4 LED support
+        led=1      enable  LED support
+        led=0      disable LED support
+  Do not enable LED support if your scsi board does not use SDMS BIOS.
+  (See 'Configuration parameters')
+
+10.2.4 Differential mode
+        diff=0 never set up diff mode
+        diff=1 set up diff mode if BIOS set it
+        diff=2 always set up diff mode
+        diff=3 set diff mode if GPIO3 is not set
+
+10.2.5 IRQ mode
+        irqm=0     always open drain
+        irqm=1     same as initial settings (assumed BIOS settings)
+        irqm=2     always totem pole
+
+10.2.6 Check SCSI BUS 
+        buschk=<option bits>
+
+    Available option bits:
+        0x0:   No check.
+        0x1:   Check and do not attach the controller on error.  
+        0x2:   Check and just warn on error.
+
+10.2.7 Suggest a default SCSI id for hosts
+        hostid=255     no id suggested.
+        hostid=#x   (0 < x < 7) x suggested for hosts SCSI id.
+
+    If a host SCSI id is available from the NVRAM, the driver will ignore 
+    any value suggested as boot option. Otherwise, if a suggested value 
+    different from 255 has been supplied, it will use it. Otherwise, it will 
+    try to deduce the value previously set in the hardware and use value 
+    7 if the hardware value is zero.
+
+10.2.8  Verbosity level
+        verb=0     minimal
+        verb=1     normal
+        verb=2     too much
+
+10.2.9 Debug mode
+        debug=0         clear debug flags
+        debug=#x   set debug flags
   #x is an integer value combining the following power-of-2 values:
   DEBUG_ALLOC       0x1
   DEBUG_PHASE       0x2
@@ -517,55 +528,17 @@ characters and digits are allowed.
   You can play safely with DEBUG_NEGO. However, some of these flags may 
   generate bunches of syslog messages. 
 
-10.2.7 Burst max
-        burst:0    burst disabled
-        burst:255  get burst length from initial IO register settings.
-        burst:#x   burst enabled (1<<#x burst transfers max)
-  #x is an integer value which is log base 2 of the burst transfers max.
-  By default the driver uses the maximum value supported by the chip.
+10.2.10 Settle delay
+        settle=n       delay for n seconds
 
-10.2.8 LED support
-        led:1      enable  LED support
-        led:0      disable LED support
-  Donnot enable LED support if your scsi board does not use SDMS BIOS.
-  (See 'Configuration parameters')
+  After a bus reset, the driver will delay for n seconds before talking
+  to any device on the bus.  The default is 3 seconds and safe mode will
+  default it to 10.
 
-10.2.9 Max wide
-        wide:1      wide scsi enabled
-        wide:0      wide scsi disabled
-  Some scsi boards use a 875 (ultra wide) and only supply narrow connectors.
-  If you have connected a wide device with a 50 pins to 68 pins cable 
-  converter, any accepted wide negotiation will break further data transfers.
-  In such a case, using "wide:0" in the bootup command will be helpfull. 
-
-10.2.10 Differential mode
-        diff:0 never set up diff mode
-        diff:1 set up diff mode if BIOS set it
-        diff:2 always set up diff mode
-        diff:3 set diff mode if GPIO3 is not set
-
-10.2.11 IRQ mode
-        irqm:0     always open drain
-        irqm:1     same as initial settings (assumed BIOS settings)
-        irqm:2     always totem pole
-
-10.2.12 Reverse probe
-        revprob:n   probe chip ids from the PCI configuration in this order:
-                    810, 815, 825, 860, 875, 885, 875A, 895, 896, 895A,
-                    1510D, 1010-33, 1010-66.
-        revprob:y   probe chip ids in the reverse order.
-
-10.2.13 Fix up PCI configuration space
-        pcifix:<option bits>
-
-    Available option bits:
-        0x0:   No attempt to fix PCI configuration space registers values.
-        0x1:   Set PCI cache-line size register if not set.
-        0x2:   Set write and invalidate bit in PCI command register.
-
-10.2.14 Serial NVRAM
-        nvram:n     do not look for serial NVRAM
-        nvram:y     test controllers for onboard serial NVRAM
+10.2.11 Serial NVRAM
+       NB: option not currently implemented.
+        nvram=n     do not look for serial NVRAM
+        nvram=y     test controllers for onboard serial NVRAM
         (alternate binary form)
         nvram=<bits options>
         0x01   look for NVRAM  (equivalent to nvram=y)
@@ -574,105 +547,28 @@ characters and digits are allowed.
         0x08   ignore NVRAM "Scan at boot time" parameter for all devices
         0x80   also attach controllers set to OFF in the NVRAM (sym53c8xx only)
 
-10.2.15 Check SCSI BUS 
-        buschk:<option bits>
-
-    Available option bits:
-        0x0:   No check.
-        0x1:   Check and do not attach the controller on error.  
-        0x2:   Check and just warn on error.
-
-10.2.16 Exclude a host from being attached
-        excl=<io_address>
+10.2.12 Exclude a host from being attached
+        excl=<io_address>,...
 
     Prevent host at a given io address from being attached.
-    For example 'sym53c8xx=excl:0xb400,excl:0xc000' indicate to the 
+    For example 'excl=0xb400,0xc000' indicate to the 
     driver not to attach hosts at address 0xb400 and 0xc000.
 
-10.2.17 Suggest a default SCSI id for hosts
-        hostid:255     no id suggested.
-        hostid:#x   (0 < x < 7) x suggested for hosts SCSI id.
-
-    If a host SCSI id is available from the NVRAM, the driver will ignore 
-    any value suggested as boot option. Otherwise, if a suggested value 
-    different from 255 has been supplied, it will use it. Otherwise, it will 
-    try to deduce the value previously set in the hardware and use value 
-    7 if the hardware value is zero.
-
-10.3 PCI configuration fix-up boot option
-
-pcifix:<option bits>
-
-Available option bits:
-    0x1:     Set PCI cache-line size register if not set.
-    0x2:     Set write and invalidate bit in PCI command register.
+10.3 Converting from old style options
 
-Use 'pcifix:3' in order to allow the driver to fix both PCI features.
+Previously, the sym2 driver accepted arguments of the form
+       sym53c8xx=tags:4,sync:10,debug:0x200
 
-Recent SYMBIOS 53C8XX scsi processors are able to use PCI read multiple 
-and PCI write and invalidate commands. These features require the 
-cache line size register to be properly set in the PCI configuration 
-space of the chips. On the other hand, chips will use PCI write and 
-invalidate commands only if the corresponding bit is set to 1 in the 
-PCI command register.
+As a result of the new module parameters, this is no longer available.
+Most of the options have remained the same, but tags has split into
+cmd_per_lun and tag_ctrl for its two different purposes.  The sample above
+would be specified as:
+       modprobe sym53c8xx cmd_per_lun=4 sync=10 debug=0x200
 
-Not all PCI bioses set the PCI cache line register and the PCI write and 
-invalidate bit in the PCI configuration space of 53C8XX chips.
-Optimized PCI accesses may be broken for some PCI/memory controllers or 
-make problems with some PCI boards.
+or on the kernel boot line as:
+       sym53c8xx.cmd_per_lun=4 sym53c8xx.sync=10 sym53c8xx.debug=0x200
 
-10.4 Serial NVRAM support boot option
-
-nvram:n     do not look for serial NVRAM
-nvram:y     test controllers for onboard serial NVRAM
-
-This option can also been entered as an hexadecimal value that allows 
-to control what information the driver will get from the NVRAM and what 
-information it will ignore.
-For details see '17. Serial NVRAM support'.
-
-When this option is enabled, the driver tries to detect all boards using 
-a Serial NVRAM. This memory is used to hold user set up parameters.
-
-The parameters the driver is able to get from the NVRAM depend on the 
-data format used, as follow:
-
-                                 Tekram format      Symbios format
-General and host parameters
-    Boot order                         N                   Y
-    Host SCSI ID                       Y                   Y
-    SCSI parity checking               Y                   Y
-    Verbose boot messages              N                   Y
-SCSI devices parameters
-    Synchronous transfer speed         Y                   Y
-    Wide 16 / Narrow                   Y                   Y
-    Tagged Command Queuing enabled     Y                   Y
-    Disconnections enabled             Y                   Y
-    Scan at boot time                  N                   Y
-
-In order to speed up the system boot, for each device configured without 
-the "scan at boot time" option, the driver forces an error on the 
-first TEST UNIT READY command received for this device.
-
-Some SDMS BIOS revisions seem to be unable to boot cleanly with very fast 
-hard disks. In such a situation you cannot configure the NVRAM with 
-optimized parameters value.
-
-The 'nvram' boot option can be entered in hexadecimal form in order 
-to ignore some options configured in the NVRAM, as follow:
-
-nvram=<bits options>
-      0x01   look for NVRAM  (equivalent to nvram=y)
-      0x02   ignore NVRAM "Synchronous negotiation" parameters for all devices
-      0x04   ignore NVRAM "Wide negotiation"  parameter for all devices
-      0x08   ignore NVRAM "Scan at boot time" parameter for all devices
-      0x80   also attach controllers set to OFF in the NVRAM (sym53c8xx only)
-
-Option 0x80 is disabled by default.
-Result is that, by default (option not set), the sym53c8xx driver will not 
-attach controllers set to OFF in the NVRAM.
-
-10.5 SCSI BUS checking boot option.
+10.4 SCSI BUS checking boot option.
 
 When this option is set to a non-zero value, the driver checks SCSI lines 
 logic state, 100 micro-seconds after having asserted the SCSI RESET line.
@@ -805,14 +701,8 @@ serial NVRAM is used by Symbios and Tekram to hold set up parameters for the
 host adaptor and it's attached drives.
 
 The Symbios NVRAM also holds data on the boot order of host adaptors in a
-system with more than one host adaptor. This enables the order of scanning
-the cards for drives to be changed from the default used during host adaptor
-detection.
-
-This can be done to a limited extent at the moment using "reverse probe" but
-this only changes the order of detection of different types of cards. The
-NVRAM boot order settings can do this as well as change the order the same
-types of cards are scanned in, something "reverse probe" cannot do.
+system with more than one host adaptor.  This information is no longer used
+as it's fundamentally incompatible with the hotplug PCI model.
 
 Tekram boards using Symbios chips, DC390W/F/U, which have NVRAM are detected
 and this is used to distinguish between Symbios compatible and Tekram host 
@@ -824,6 +714,26 @@ used together with the Symbios cards using all their features, including
 enabled when using Tekram cards. It does nothing useful for Tekram host
 adaptors but does not cause problems either.)
 
+The parameters the driver is able to get from the NVRAM depend on the 
+data format used, as follow:
+
+                                 Tekram format      Symbios format
+General and host parameters
+    Boot order                         N                   Y
+    Host SCSI ID                       Y                   Y
+    SCSI parity checking               Y                   Y
+    Verbose boot messages              N                   Y
+SCSI devices parameters
+    Synchronous transfer speed         Y                   Y
+    Wide 16 / Narrow                   Y                   Y
+    Tagged Command Queuing enabled     Y                   Y
+    Disconnections enabled             Y                   Y
+    Scan at boot time                  N                   Y
+
+In order to speed up the system boot, for each device configured without 
+the "scan at boot time" option, the driver forces an error on the 
+first TEST UNIT READY command received for this device.
+
 
 17.2 Symbios NVRAM layout
 
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
index 03f9eda..0f3b240 100644 (file)
@@ -1,6 +1,6 @@
 Sony Programmable I/O Control Device Driver Readme
 --------------------------------------------------
-       Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+       Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
        Copyright (C) 2001-2002 Alcôve <www.alcove.com>
        Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
        Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
@@ -23,16 +23,18 @@ generate, like:
 
 Those events (see linux/sonypi.h) can be polled using the character device node
 /dev/sonypi (major 10, minor auto allocated or specified as a option).
-
 A simple daemon which translates the jogdial movements into mouse wheel events
 can be downloaded at: <http://popies.net/sonypi/>
 
+Another option to intercept the events is to get them directly through the
+input layer.
+
 This driver supports also some ioctl commands for setting the LCD screen
-brightness and querying the batteries charge information (some more 
+brightness and querying the batteries charge information (some more
 commands may be added in the future).
 
 This driver can also be used to set the camera controls on Picturebook series
-(brightness, contrast etc), and is used by the video4linux driver for the 
+(brightness, contrast etc), and is used by the video4linux driver for the
 Motion Eye camera.
 
 Please note that this driver was created by reverse engineering the Windows
@@ -42,15 +44,12 @@ specs for its laptops. If someone convinces them to do so, drop me a note.
 Driver options:
 ---------------
 
-Several options can be passed to the sonypi driver, either by adding them
-to /etc/modprobe.conf file, when the driver is compiled as a module or by
-adding the following to the kernel command line (in your bootloader):
-
-       sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,mask[,useinput]]]]]]
+Several options can be passed to the sonypi driver using the standard
+module argument syntax (<param>=<value> when passing the option to the
+module or sonypi.<param>=<value> on the kernel boot line when sonypi is
+statically linked into the kernel). Those options are:
 
-where:
-
-       minor:          minor number of the misc device /dev/sonypi, 
+       minor:          minor number of the misc device /dev/sonypi,
                        default is -1 (automatic allocation, see /proc/misc
                        or kernel logs)
 
@@ -62,14 +61,14 @@ where:
                        get enabled unless you set this parameter to 1.
                        Do not use this option unless it's actually necessary,
                        some Vaio models don't deal well with this option.
-                       This option is available only if the kernel is 
+                       This option is available only if the kernel is
                        compiled without ACPI support (since it conflicts
-                       with it and it shouldn't be required anyway if 
+                       with it and it shouldn't be required anyway if
                        ACPI is already enabled).
 
-       verbose:        set to 1 to print unknown events received from the 
+       verbose:        set to 1 to print unknown events received from the
                        sonypi device.
-                       set to 2 to print all events received from the 
+                       set to 2 to print all events received from the
                        sonypi device.
 
        compat:         uses some compatibility code for enabling the sonypi
@@ -78,14 +77,15 @@ where:
                        add this option and report to the author.
 
        mask:           event mask telling the driver what events will be
-                       reported to the user. This parameter is required for some 
-                       Vaio models where the hardware reuses values used in 
-                       other Vaio models (like the FX series who does not
-                       have a jogdial but reuses the jogdial events for
+                       reported to the user. This parameter is required for
+                       some Vaio models where the hardware reuses values
+                       used in other Vaio models (like the FX series who does
+                       not have a jogdial but reuses the jogdial events for
                        programmable keys events). The default event mask is
-                       set to 0xffffffff, meaning that all possible events will be
-                       tried. You can use the following bits to construct
-                       your own event mask (from drivers/char/sonypi.h):
+                       set to 0xffffffff, meaning that all possible events
+                       will be tried. You can use the following bits to
+                       construct your own event mask (from
+                       drivers/char/sonypi.h):
                                SONYPI_JOGGER_MASK              0x0001
                                SONYPI_CAPTURE_MASK             0x0002
                                SONYPI_FNKEY_MASK               0x0004
@@ -100,10 +100,10 @@ where:
                                SONYPI_MEMORYSTICK_MASK         0x0800
                                SONYPI_BATTERY_MASK             0x1000
 
-       useinput:       if set (which is the default) jogdial events are
-                       forwarded to the input subsystem as mouse wheel
-                       events.
-                       
+       useinput:       if set (which is the default) two input devices are
+                       created, one which interprets the jogdial events as
+                       mouse events, the other one which acts like a
+                       keyboard reporting the pressing of the special keys.
 
 Module use:
 -----------
@@ -126,17 +126,17 @@ Bugs:
          external monitor on/off. There is no workaround yet, since this
          driver disables all APM management for those keys, by enabling the
          ACPI management (and the ACPI core stuff is not complete yet). If
-         you have one of those laptops with working Fn keys and want to 
+         you have one of those laptops with working Fn keys and want to
          continue to use them, don't use this driver.
 
        - some users reported that the laptop speed is lower (dhrystone
          tested) when using the driver with the fnkeyinit parameter. I cannot
          reproduce it on my laptop and not all users have this problem.
-         This happens because the fnkeyinit parameter enables the ACPI 
-         mode (but without additional ACPI control, like processor 
+         This happens because the fnkeyinit parameter enables the ACPI
+         mode (but without additional ACPI control, like processor
          speed handling etc). Use ACPI instead of APM if it works on your
          laptop.
-       
+
        - since all development was done by reverse engineering, there is
          _absolutely no guarantee_ that this driver will not crash your
          laptop. Permanently.
index dcc6c85..ccda41b 100644 (file)
@@ -49,17 +49,15 @@ The following PCI drivers support the joystick natively.
     cs46xx     N/A             N/A
     es1938     N/A             N/A
     es1968     joystick        0 = disable (default), 1 = enable
-    intel8x0(*1)joystick       0 = disable (default), 1 = enable
     sonicvibes N/A             N/A
     trident    N/A             N/A
-    via82xx(*2)        joystick        0 = disable (default), 1 = enable
+    via82xx(*1)        joystick        0 = disable (default), 1 = enable
     ymfpci     joystick_port   0 = disable (default), 1 = auto-detect,
-                                manual: 0x201, 0x202, 0x204, 0x205(*3)
+                                manual: 0x201, 0x202, 0x204, 0x205(*2)
     ---------------------------------------------------------------------------
 
-    *1)  not all chips support joystick
-    *2)  VIA686A/B only
-    *3)  With YMF744/754 chips, the port address can be chosen arbitrarily
+    *1)  VIA686A/B only
+    *2)  With YMF744/754 chips, the port address can be chosen arbitrarily
 
 The following drivers don't support gameport natively, but there are
 additional modules.  Load the corresponding module to add the gameport
index 0e6c92d..e691d74 100644 (file)
@@ -59,8 +59,9 @@ sound.o # The sound driver
 uart401.o # Used by sb, maybe other cards
 
  Whichever card you have, try feeding it the options that would be the
-default if you were making the driver wired, not as modules. You can look
-at the init_module() code for the card to see what args are expected.
+default if you were making the driver wired, not as modules. You can
+look at function referred to by module_init() for the card to see what
+args are expected.
 
  Note that at present there is no way to configure the io, irq and other
 parameters for the modular drivers as one does for the wired drivers.. One
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.
index d9fefd5..e3b6085 100644 (file)
@@ -9,32 +9,33 @@ 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
+interpolation between ticks. 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.
+(or the device drivers - like HPET) may register time interpolators.
 These are typically defined in the following way:
 
-static struct time_interpolator my_interpolator;
+static struct time_interpolator my_interpolator {
+       .frequency = MY_FREQUENCY,
+       .source = TIME_SOURCE_MMIO32,
+       .shift = 8,             /* scaling for higher accuracy */
+       .drift = -1,            /* Unknown drift */
+       .jitter = 0             /* time source is stable */
+};
 
 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.
+For more details see include/linux/timex.h and kernel/timer.c.
 
-Christoph Lameter <christoph@lameter.com>, September 8, 2004
+Christoph Lameter <christoph@lameter.com>, October 31, 2004
 
index 773b9a2..67133ba 100644 (file)
@@ -4,7 +4,7 @@
 
 
 Author: Romain Lievin
-Homepage: http://lpg.ticalc.org/prj_dev
+Homepage: http://lpg.ticalc.org/prj_tidev/index.html
 
 
 INTRODUCTION:
@@ -12,31 +12,30 @@ INTRODUCTION:
 This is a driver for the very common home-made parallel link cable, a cable 
 designed for connecting TI8x/9x graphing calculators (handhelds) to a computer
 or workstation (Alpha, Sparc). Given that driver is built on parport, the 
-parallel port abstraction layer, this driver is independent of the platform.
+parallel port abstraction layer, this driver is architecture-independent.
 
 It can also be used with another device plugged on the same port (such as a
-ZIP drive). I have a 100MB ZIP and both of them work fine !
+ZIP drive). I have a 100MB ZIP and both of them work fine!
 
 If you need more information, please visit the 'TI drivers' homepage at the URL
 above.
 
 WHAT YOU NEED:
 
-A TI calculator of course and a program capable to communicate with your 
-calculator.
-TiLP will work for sure (since I am his developer !). yal92 may be able to use
+A TI calculator and a program capable of communicating with your calculator.
+
+TiLP will work for sure (since I am its developer!). yal92 may be able to use
 it by changing tidev for tipar (may require some hacking...).
 
 HOW TO USE IT:
 
 You must have first compiled parport support (CONFIG_PARPORT_DEV): either 
 compiled in your kernel, either as a module. 
-This driver supports the new device hierarchy (devfs).
 
-Next, (as root) from your appropriate modules directory (lib/modules/2.5.XX):
+Next, (as root):
 
        modprobe parport
-       insmod tipar.o
+       modprobe tipar
 
 If it is not already there (it usually is), create the device:
 
@@ -47,14 +46,14 @@ If it is not already there (it usually is), create the device:
 You will have to set permissions on this device to allow you to read/write
 from it:
 
-       chmod 666 /dev/tipar?
+       chmod 666 /dev/tipar[0..2]
        
 Now you are ready to run a linking program such as TiLP. Be sure to configure 
 it properly (RTFM).
        
 MODULE PARAMETERS:
 
-  You can set these with:  insmod tipar NAME=VALUE
+  You can set these with:  modprobe tipar NAME=VALUE
   There is currently no way to set these on a per-cable basis.
 
   NAME: timeout
@@ -66,11 +65,12 @@ MODULE PARAMETERS:
   NAME: delay
   TYPE: integer
   DEFAULT: 10
-  DESC: Inter-bit delay in micro-seconds. An lower value gives an higher data 
+  DESC: Inter-bit delay in micro-seconds. A lower value gives an higher data
        rate but makes transmission less reliable.
 
 These parameters can be changed at run time by any program via ioctl(2) calls 
-as listed in ./include/linux/ticable.h
+as listed in ./include/linux/ticable.h.
+
 Rather than write 50 pages describing the ioctl() and so on, it is
 perhaps more useful you look at ticables library (dev_link.c) that demonstrates
 how to use them, and demonstrates the features of the driver. This is
index a496056..5f6dc12 100644 (file)
@@ -49,10 +49,9 @@ open()               -       Called when the line discipline is attached to
                        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.
+write()                -       A process is writing data 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.
 
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.
+
+
index d720415..81cbb52 100644 (file)
@@ -1,5 +1,6 @@
 -------------------------------------------------------------------------
 Readme for Linux device driver for the Texas Instruments SilverLink cable
+and direct USB cable provided by some TI's handhelds.
 -------------------------------------------------------------------------
 
 Author: Romain Liévin & Julien Blache
@@ -9,7 +10,8 @@ INTRODUCTION:
 
 This is a driver for the TI-GRAPH LINK USB (aka SilverLink) cable, a cable 
 designed by TI for connecting their TI8x/9x calculators to a computer 
-(PC or Mac usually).
+(PC or Mac usually). It has been extended to support the USB port offered by
+some latest TI handhelds (TI84+ and TI89 Titanium).
 
 If you need more information, please visit the 'SilverLink drivers' homepage 
 at the above URL.
@@ -73,4 +75,4 @@ this driver but he better knows the Mac OS-X driver.
 CREDITS:
 
 The code is based on dabusb.c, printer.c and scanner.c !
-The driver has been developed independently of Texas Instruments.
+The driver has been developed independently of Texas Instruments Inc.
index 3999069..18ceabd 100644 (file)
@@ -1,7 +1,7 @@
 
-                        SN9C10[12] PC Camera Controllers
+                         SN9C10x PC Camera Controllers
                                 Driver for Linux
-                        ================================
+                         =============================
 
                                - Documentation -
 
@@ -9,28 +9,32 @@
 Index
 =====
 1.  Copyright
-2.  License
-3.  Overview
-4.  Module dependencies
-5.  Module loading
-6.  Module parameters
-7.  Optional device control through "sysfs"
-8.  Supported devices
-9.  How to add support for new image sensors
-10. Notes for V4L2 application developers
-11. Contact information
-12. Credits
+2.  Disclaimer
+3.  License
+4.  Overview
+5.  Driver installation
+6.  Module loading
+7.  Module parameters
+8.  Optional device control through "sysfs"
+9.  Supported devices
+10. How to add support for new image sensors
+11. Notes for V4L2 application developers
+12. Contact information
+13. Credits
 
 
 1. Copyright
 ============
 Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>
 
+
+2. Disclaimer
+=============
 SONiX is a trademark of SONiX Technology Company Limited, inc.
-This driver is not sponsored or developed by SONiX.
+This software is not sponsored or developed by SONiX.
 
 
-2. License
+3. License
 ==========
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -47,28 +51,52 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 
-3. Overview
+4. Overview
 ===========
-This driver attempts to support the video streaming capabilities of the devices
-mounting the SONiX SN9C101 or SONiX SN9C102 PC Camera Controllers.
+This driver attempts to support the video and audio streaming capabilities of
+the devices mounting the SONiX SN9C101, SN9C102 and SN9C103 (or SUI-102) PC
+Camera Controllers.
 
-- It's worth to note that SONiX has never collaborated with me during the
-development of this project, despite of several requests for enough detailed
+It's worth to note that SONiX has never collaborated with the author during the
+development of this project, despite several requests for enough detailed
 specifications of the register tables, compression engine and video data format
-of the above chips -
-
-Up to 64 cameras can be handled at the same time. They can be connected and
-disconnected from the host many times without turning off the computer, if
-your system supports the hotplug facility.
+of the above chips.
 
 The driver relies on the Video4Linux2 and USB core modules. It has been
 designed to run properly on SMP systems as well.
 
-The latest version of the SN9C10[12] driver can be found at the following URL:
-http://go.lamarinapunto.com/
-
-
-4. Module dependencies
+The latest version of the SN9C10x driver can be found at the following URL:
+http://www.linux-projects.org/
+
+Some of the features of the driver are:
+
+- full compliance with the Video4Linux2 API (see also "Notes for V4L2
+  application developers" paragraph);
+- available mmap or read/poll methods for video streaming through isochronous
+  data transfers;
+- automatic detection of image sensor;
+- support for any window resolutions and optional panning within the maximum
+  pixel area of image sensor;
+- image downscaling with arbitrary scaling factors from 1, 2 and 4 in both
+  directions (see "Notes for V4L2 application developers" paragraph);
+- two different video formats for uncompressed or compressed data (see also
+  "Notes for V4L2 application developers" paragraph);
+- full support for the capabilities of many of the possible image sensors that
+  can be connected to the SN9C10x bridges, including, for istance, red, green,
+  blue and global gain adjustments and exposure (see "Supported devices"
+  paragraph for details);
+- use of default color settings for sunlight conditions;
+- dynamic I/O interface for both SN9C10x and image sensor control (see
+  "Optional device control through 'sysfs'" paragraph);
+- dynamic driver control thanks to various module parameters (see "Module
+  parameters" paragraph);
+- up to 64 cameras can be handled at the same time; they can be connected and
+  disconnected from the host many times without turning off the computer, if
+  your system supports hotplugging;
+- no known bugs.
+
+
+5. Module dependencies
 ======================
 For it to work properly, the driver needs kernel support for Video4Linux and
 USB.
@@ -100,7 +128,7 @@ And finally:
        CONFIG_USB_SN9C102=m
 
 
-5. Module loading
+6. Module loading
 =================
 To use the driver, it is necessary to load the "sn9c102" module into memory
 after every other module required: "videodev", "usbcore" and, depending on
@@ -108,7 +136,6 @@ the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
 
 Loading can be done as shown below:
 
-       [root@localhost home]# modprobe usbcore
        [root@localhost home]# modprobe sn9c102
 
 At this point the devices should be recognized. You can invoke "dmesg" to
@@ -117,17 +144,17 @@ analyze kernel messages and verify that the loading process has gone well:
        [user@localhost home]$ dmesg
 
 
-6. Module parameters
+7. Module parameters
 ====================
 Module parameters are listed below:
 -------------------------------------------------------------------------------
 Name:           video_nr
-Type:           int array (min = 0, max = 32)
+Type:           int array (min = 0, max = 64)
 Syntax:         <-1|n[,...]> 
 Description:    Specify V4L2 minor mode number:
                 -1 = use next available
                  n = use minor number n
-                You can specify up to 32 cameras this way.
+                You can specify up to 64 cameras this way.
                 For example:
                 video_nr=-1,2,-1 would assign minor number 2 to the second
                 recognized camera and use auto for the first one and for every
@@ -143,24 +170,29 @@ Description:    Debugging information level, from 0 to 3:
                 2 = significant informations
                 3 = more verbose messages
                 Level 3 is useful for testing only, when only one device
-                is used.
+                is used. It also shows some more informations about the
+                hardware being detected. This parameter can be changed at
+                runtime thanks to the /sys filesystem.
 Default:        2
 -------------------------------------------------------------------------------
 
 
-7. Optional device control through "sysfs"
+8. Optional device control through "sysfs"
 ==========================================
-It is possible to read and write both the SN9C10[12] and the image sensor
+It is possible to read and write both the SN9C10x and the image sensor
 registers by using the "sysfs" filesystem interface.
 
-Every time a supported device is recognized, a read-only file named "green" is
+Every time a supported device is recognized, a write-only file named "green" is
 created in the /sys/class/video4linux/videoX directory. You can set the green
 channel's gain by writing the desired value to it. The value may range from 0
-to 15.
+to 15 for SN9C101 or SN9C102 bridges, from 0 to 127 for SN9C103 bridges.
+Similarly, only for SN9C103 controllers, blue and red gain control files are
+available in the same directory, for which accepted values may range from 0 to
+127.
 
 There are other four entries in the directory above for each registered camera:
 "reg", "val", "i2c_reg" and "i2c_val". The first two files control the
-SN9C10[12] bridge, while the other two control the sensor chip. "reg" and
+SN9C10x bridge, while the other two control the sensor chip. "reg" and
 "i2c_reg" hold the values of the current register index where the following
 reading/writing operations are addressed at through "val" and "i2c_val". Their
 use is not intended for end-users, unless you know what you are doing. Note
@@ -169,48 +201,77 @@ support the standard I2C protocol. Also, remember that you must be logged in as
 root before writing to them.
 
 As an example, suppose we were to want to read the value contained in the
-register number 1 of the sensor register table - which usually is the product
+register number 1 of the sensor register table - which is usually the product
 identifier - of the camera registered as "/dev/video0":
 
        [root@localhost #] cd /sys/class/video4linux/video0
        [root@localhost #] echo 1 > i2c_reg
        [root@localhost #] cat i2c_val
 
-Now let's set the green gain's register of the SN9C10[12] chip to 2:
+Note that "cat" will fail if sensor registers cannot be read.
+
+Now let's set the green gain's register of the SN9C101 or SN9C102 chips to 2:
 
        [root@localhost #] echo 0x11 > reg
        [root@localhost #] echo 2 > val
 
-Note that the SN9C10[12] always returns 0 when some of its registers are read.
+Note that the SN9C10x always returns 0 when some of its registers are read.
 To avoid race conditions, all the I/O accesses to the files are serialized.
 
 
-8. Supported devices
+9. Supported devices
 ====================
-- I won't mention any of the names of the companies as well as their products
-here. They have never collaborated with me, so no advertising -
+None of the names of the companies as well as their products will be mentioned
+here. They have never collaborated with the author, so no advertising.
 
 From the point of view of a driver, what unambiguously identify a device are
 its vendor and product USB identifiers. Below is a list of known identifiers of
-devices mounting the SN9C10[12] PC camera controllers:
+devices mounting the SN9C10x PC camera controllers:
 
 Vendor ID  Product ID
 ---------  ----------
-0xc45      0x6001
-0xc45      0x6005
-0xc45      0x6009
-0xc45      0x600d
-0xc45      0x6024
-0xc45      0x6025
-0xc45      0x6028
-0xc45      0x6029
-0xc45      0x602a
-0xc45      0x602c
-0xc45      0x6030
-
-The list above does NOT imply that all those devices work with this driver: up
-until now only the ones that mount the following image sensors are supported.
-Kernel messages will always tell you whether this is the case:
+0x0c45     0x6001
+0x0c45     0x6005
+0x0c45     0x6009
+0x0c45     0x600d
+0x0c45     0x6024
+0x0c45     0x6025
+0x0c45     0x6028
+0x0c45     0x6029
+0x0c45     0x602a
+0x0c45     0x602b
+0x0c45     0x602c
+0x0c45     0x6030
+0x0c45     0x6080
+0x0c45     0x6082
+0x0c45     0x6083
+0x0c45     0x6088
+0x0c45     0x608a
+0x0c45     0x608b
+0x0c45     0x608c
+0x0c45     0x608e
+0x0c45     0x608f
+0x0c45     0x60a0
+0x0c45     0x60a2
+0x0c45     0x60a3
+0x0c45     0x60a8
+0x0c45     0x60aa
+0x0c45     0x60ab
+0x0c45     0x60ac
+0x0c45     0x60ae
+0x0c45     0x60af
+0x0c45     0x60b0
+0x0c45     0x60b2
+0x0c45     0x60b3
+0x0c45     0x60b8
+0x0c45     0x60ba
+0x0c45     0x60bb
+0x0c45     0x60bc
+0x0c45     0x60be
+
+The list above does not imply that all those devices work with this driver: up
+until now only the ones that mount the following image sensors are supported;
+kernel messages will always tell you whether this is the case:
 
 Model       Manufacturer
 -----       ------------
@@ -219,30 +280,33 @@ PAS202BCB   PixArt Imaging Inc.
 TAS5110C1B  Taiwan Advanced Sensor Corporation
 TAS5130D1B  Taiwan Advanced Sensor Corporation
 
+All the available control settings of each image sensor are supported through
+the V4L2 interface.
+
 If you think your camera is based on the above hardware and is not actually
 listed in the above table, you may try to add the specific USB VendorID and
 ProductID identifiers to the sn9c102_id_table[] in the file "sn9c102_sensor.h";
 then compile, load the module again and look at the kernel output.
-If this works, please send an email to me reporting the kernel messages, so
-that I will add a new entry in the list of supported devices.
+If this works, please send an email to the author reporting the kernel
+messages, so that a new entry in the list of supported devices can be added.
 
 Donations of new models for further testing and support would be much
-appreciated. I won't add official support for hardware that I don't actually
-have.
+appreciated. Non-available hardware won't be supported by the author of this
+driver.
 
 
-9. How to add support for new image sensors
-===========================================
+10. How to add support for new image sensors
+============================================
 It should be easy to write code for new sensors by using the small API that I
 have created for this purpose, which is present in "sn9c102_sensor.h"
 (documentation is included there). As an example, have a look at the code in
 "sn9c102_pas106b.c", which uses the mentioned interface.
 
-At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA),
-MI03 (VGA), OV7620 (VGA).
+At the moment, possible unsupported image sensors are: HV7131x series (VGA),
+MI03x series (VGA), OV7620 (VGA), OV7630 (VGA), CIS-VF10 (VGA).
 
 
-10. Notes for V4L2 application developers
+11. Notes for V4L2 application developers
 =========================================
 This driver follows the V4L2 API specifications. In particular, it enforces two
 rules:
@@ -254,18 +318,29 @@ device to switch to the other I/O method;
 - previously mapped buffer memory must always be unmapped before calling any
 of the "VIDIOC_S_CROP", "VIDIOC_TRY_FMT" and "VIDIOC_S_FMT" ioctl's. The same
 number of buffers as before will be allocated again to match the size of the
-new video frames, so you have to map them again before any I/O attempts.
+new video frames, so you have to map the buffers again before any I/O attempts
+on them.
 
 Consistently with the hardware limits, this driver also supports image
 downscaling with arbitrary scaling factors from 1, 2 and 4 in both directions.
-However the V4L2 API specifications don't correctly define how the scaling
-factor can be choosen arbitrarily by the "negotiation" of the "source" and
+However, the V4L2 API specifications don't correctly define how the scaling
+factor can be chosen arbitrarily by the "negotiation" of the "source" and
 "target" rectangles. To work around this flaw, we have added the convention
 that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the
 scaling factor is restored to 1.
 
+This driver supports two different video formats: the first one is the "8-bit
+Sequential Bayer" format and can be used to obtain uncompressed video data
+from the device through the current I/O method, while the second one provides
+"raw" compressed video data (without the initial and final frame headers). The
+compression quality may vary from 0 to 1 and can be selected or queried thanks
+to the VIDIOC_S_JPEGCOMP and VIDIOC_G_JPEGCOMP V4L2 ioctl's. For maximum
+flexibility, the default active video format depends on how the image sensor
+being used is initialized (as described in the documentation of the API for the
+image sensors supplied by this driver).
+
 
-11. Contact information
+12. Contact information
 =======================
 I may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
 
@@ -274,7 +349,7 @@ My public 1024-bit key should be available at any keyserver; the fingerprint
 is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
 
 
-12. Credits
+13. Credits
 ===========
 I would thank the following persons:
 
index d431f19..f001cd9 100644 (file)
@@ -211,6 +211,62 @@ ZyXEL omni.net lcd plus ISDN TA
   azummo@towertech.it
 
 
+Cypress M8 CY4601 Family Serial Driver
+
+  This driver was in most part developed by Neil "koyama" Whelchel.  It
+  has been improved since that previous form to support dynamic serial
+  line settings and improved line handling.  The driver is for the most
+  part stable and has been tested on an smp machine. (dual p2)
+
+    Chipsets supported under CY4601 family:
+       
+               CY7C63723, CY7C63742, CY7C63743, CY7C64013
+
+    Devices supported:
+
+               -DeLorme's USB Earthmate (SiRF Star II lp arch)
+               -Cypress HID->COM RS232 adapter
+       
+               Note: Cypress Semiconductor claims no affiliation with the
+                       the hid->com device.
+
+       Most devices using chipsets under the CY4601 family should
+     work with the driver.  As long as they stay true to the CY4601
+     usbserial specification.
+
+    Technical notes:
+
+        The Earthmate starts out at 4800 8N1 by default... the driver will
+       upon start init to this setting.  usbserial core provides the rest
+       of the termios settings, along with some custom termios so that the
+       output is in proper format and parsable.
+       
+       The device can be put into sirf mode by issuing NMEA command:
+               $PSRF100,<protocol>,<baud>,<databits>,<stopbits>,<parity>*CHECKSUM
+               $PSRF100,0,9600,8,1,0*0C
+
+               It should then be sufficient to change the port termios to match this
+               to begin communicating.
+
+       As far as I can tell it supports pretty much every sirf command as
+       documented online available with firmware 2.31, with some unknown
+       message ids.
+
+       The hid->com adapter can run at a maximum baud of 115200bps.  Please note
+       that the device has trouble or is incapable of raising line voltage properly.
+       It will be fine with null modem links, as long as you do not try to link two
+       together without hacking the adapter to set the line high.
+
+       The driver is smp safe.  Performance with the driver is rather low when using
+       it for transfering files.  This is being worked on, but I would be willing to
+       accept patches.  An urb queue or packet buffer would likely fit the bill here.
+
+       If you have any questions, problems, patches, feature requests, etc. you can
+       contact me here via email:
+                                       dignome@gmail.com
+               (your problems/patches can alternately be submitted to usb-devel)
+
+
 Digi AccelePort Driver
 
   This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port
index 5adcd25..2137da9 100644 (file)
@@ -1,12 +1,12 @@
 Vaio Picturebook Motion Eye Camera Driver Readme
 ------------------------------------------------
-       Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+       Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
        Copyright (C) 2001-2002 Alcôve <www.alcove.com>
        Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enable the use of video4linux compatible applications with the
-Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O 
-Control Device" driver (which can be found in the "Character drivers" 
+Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O
+Control Device" driver (which can be found in the "Character drivers"
 section of the kernel configuration utility) to be compiled and installed
 (using its "camera=1" parameter).
 
@@ -24,7 +24,7 @@ This driver supports the 'second' version of the MotionEye camera :)
 The first version was connected directly on the video bus of the Neomagic
 video card and is unsupported.
 
-The second one, made by Kawasaki Steel is fully supported by this 
+The second one, made by Kawasaki Steel is fully supported by this
 driver (PCI vendor/device is 0x136b/0xff01)
 
 The third one, present in recent (more or less last year) Picturebooks
@@ -41,13 +41,12 @@ little information if any is available for this camera
 Driver options:
 ---------------
 
-Several options can be passed to the meye driver, either by adding them
-to /etc/modprobe.conf file, when the driver is compiled as a module, or
-by adding the following to the kernel command line (in your bootloader):
+Several options can be passed to the meye driver using the standard
+module argument syntax (<param>=<value> when passing the option to the
+module or meye.<param>=<value> on the kernel boot line when meye is
+statically linked into the kernel). Those options are:
 
-       meye=gbuffers[,gbufsize[,video_nr]]
-
-where:
+       forcev4l1:      force use of V4L1 API instead of V4L2
 
        gbuffers:       number of capture buffers, default is 2 (32 max)
 
@@ -81,8 +80,9 @@ Usage:
 Private API:
 ------------
 
-       The driver supports frame grabbing with the video4linux API, so
-       all video4linux tools (like xawtv) should work with this driver.
+       The driver supports frame grabbing with the video4linux API
+       (either v4l1 or v4l2), so all video4linux tools (like xawtv)
+       should work with this driver.
 
        Besides the video4linux interface, the driver has a private interface
        for accessing the Motion Eye extended parameters (camera sharpness,
@@ -116,7 +116,7 @@ Private API:
        MEYEIOC_STILLJCAPT
                Takes a snapshot in an uncompressed or compressed jpeg format.
                This ioctl blocks until the snapshot is done and returns (for
-               jpeg snapshot) the size of the image. The image data is 
+               jpeg snapshot) the size of the image. The image data is
                available from the first mmap'ed buffer.
 
        Look at the 'motioneye' application code for an actual example.
@@ -124,13 +124,7 @@ Private API:
 Bugs / Todo:
 ------------
 
-       - overlay output is not supported (although the camera is capable of).
-               (it should not be too hard to to it, provided we found how...)
-               
-       - mjpeg hardware playback doesn't work (depends on overlay...)
+       - the driver could be much cleaned up by removing the v4l1 support.
+         However, this means all v4l1-only applications will stop working.
 
-       - rewrite the driver to use some common video4linux API for snapshot
-         and mjpeg capture. Unfortunately, video4linux1 does not permit it,
-         the BUZ API seems to be targeted to TV cards only. The video4linux 2
-         API may be an option, if it goes into the kernel (maybe 2.5 
-         material ?).
+       - 'motioneye' still uses the meye private v4l1 API extensions.
index 9db560e..21c7b1f 100644 (file)
@@ -22,6 +22,9 @@ The overcommit policy is set via the sysctl `vm.overcommit_memory'.
 
 The overcommit percentage is set via `vm.overcommit_ratio'.
 
+The current overcommit limit and amount committed are viewable in
+/proc/meminfo as CommitLimit and Committed_AS respectively.
+
 Gotchas
 -------
 
index 7f8570a..d126070 100644 (file)
@@ -87,22 +87,8 @@ Non Executable Mappings
 
   noexec=on|off
 
-  on      Enable
+  on      Enable(default)
   off     Disable
-  noforce (default) Don't enable by default for heap/stack/data,
-          but allow PROT_EXEC to be effective
-
-  noexec32=opt{,opt}
-
-  Control the no exec default for 32bit processes.
-  Requires noexec=on or noexec=noforce to be effective.
-
-  Valid options:
-     all,on    Heap,stack,data is non executable.
-     off       (default) Heap,stack,data is executable
-     stack     Stack is non executable, heap/data is.
-     force     Don't imply PROT_EXEC for PROT_READ
-     compat    (default) Imply PROT_EXEC for PROT_READ
 
 SMP
 
index 6643ae2..31c081c 100644 (file)
@@ -1,5 +1,6 @@
 OUTPUT_FORMAT("elf64-alpha")
 ENTRY(__start)
+printk = srm_printk;
 SECTIONS
 {
   . = 0x20000000;
index f5ab2a4..ec53c28 100644 (file)
@@ -26,6 +26,8 @@ extern unsigned long switch_to_osf_pal(unsigned long nr,
        struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
        unsigned long *vptb);
 
+extern void move_stack(unsigned long new_stack);
+
 struct hwrpb_struct *hwrpb = INIT_HWRPB;
 static struct pcb_struct pcb_va[1];
 
@@ -118,12 +120,10 @@ static inline void
 runkernel(void)
 {
        __asm__ __volatile__(
-               "bis %1,%1,$30\n\t"
                "bis %0,%0,$27\n\t"
                "jmp ($27)"
                : /* no outputs: it doesn't even return */
-               : "r" (START_ADDR),
-                 "r" (PAGE_SIZE + INIT_STACK));
+               : "r" (START_ADDR));
 }
 
 extern char _end;
@@ -147,9 +147,7 @@ start_kernel(void)
         */
        static long nbytes;
        static char envval[256] __attribute__((aligned(8)));
-#ifdef INITRD_IMAGE_SIZE
        static unsigned long initrd_start;
-#endif
 
        srm_printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n");
        if (INIT_HWRPB->pagesize != 8192) {
@@ -164,13 +162,20 @@ start_kernel(void)
        }
        pal_init();
 
-#ifdef INITRD_IMAGE_SIZE
        /* The initrd must be page-aligned.  See below for the 
           cause of the magic number 5.  */
-       initrd_start = ((START_ADDR + 5*KERNEL_SIZE) | (PAGE_SIZE-1)) + 1;
+       initrd_start = ((START_ADDR + 5*KERNEL_SIZE + PAGE_SIZE) |
+                       (PAGE_SIZE-1)) + 1;
+#ifdef INITRD_IMAGE_SIZE
        srm_printk("Initrd positioned at %#lx\n", initrd_start);
 #endif
 
+       /*
+        * Move the stack to a safe place to ensure it won't be
+        * overwritten by kernel image.
+        */
+       move_stack(initrd_start - PAGE_SIZE);
+
        nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
        if (nbytes < 0 || nbytes >= sizeof(envval)) {
                nbytes = 0;
index e0d808f..a6657f2 100644 (file)
@@ -41,9 +41,6 @@
 #undef DEBUG_ADDRESSES
 #undef DEBUG_LAST_STEPS
 
-#define DEBUG_SP(x) \
-    {register long sp asm("30"); srm_printk("%s (sp=%lx)\n", x, sp);}
-
 extern unsigned long switch_to_osf_pal(unsigned long nr,
        struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
        unsigned long *vptb);
@@ -51,6 +48,8 @@ extern unsigned long switch_to_osf_pal(unsigned long nr,
 extern int decompress_kernel(void* destination, void *source,
                             size_t ksize, size_t kzsize);
 
+extern void move_stack(unsigned long new_stack);
+
 struct hwrpb_struct *hwrpb = INIT_HWRPB;
 static struct pcb_struct pcb_va[1];
 
@@ -163,12 +162,10 @@ static inline void
 runkernel(void)
 {
        __asm__ __volatile__(
-               "bis %1,%1,$30\n\t"
                "bis %0,%0,$27\n\t"
                "jmp ($27)"
                : /* no outputs: it doesn't even return */
-               : "r" (START_ADDR),
-                 "r" (PAGE_SIZE + INIT_STACK));
+               : "r" (START_ADDR));
 }
 
 /* Must record the SP (it is virtual) on entry, so we can make sure
@@ -253,7 +250,9 @@ extern char _end;
    for "bootmem" anyway.
 */
 #define K_COPY_IMAGE_START     NEXT_PAGE(K_KERNEL_IMAGE_END)
-#define K_INITRD_START         NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE)
+/* Reserve one page below INITRD for the new stack. */
+#define K_INITRD_START \
+    NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE + PAGE_SIZE)
 #define K_COPY_IMAGE_END \
     (K_INITRD_START + REAL_INITRD_SIZE + MALLOC_AREA_SIZE)
 #define K_COPY_IMAGE_SIZE \
@@ -419,8 +418,7 @@ start_kernel(void)
                   initrd_image_start,
                   INITRD_IMAGE_SIZE);
 #endif
-       memcpy((void *)initrd_image_start,
-              (void *)V_INITRD_START,
+       memcpy((void *)initrd_image_start, (void *)V_INITRD_START,
               INITRD_IMAGE_SIZE);
 
 #endif /* INITRD_IMAGE_SIZE */
@@ -436,9 +434,14 @@ start_kernel(void)
                           K_KERNEL_IMAGE_START,
                           (unsigned)KERNEL_SIZE);
 #endif
+               /*
+                * Move the stack to a safe place to ensure it won't be
+                * overwritten by kernel image.
+                */
+               move_stack(initrd_image_start - PAGE_SIZE);
+
                memcpy((void *)K_KERNEL_IMAGE_START,
-                      (void *)uncompressed_image_start,
-                      KERNEL_SIZE);
+                      (void *)uncompressed_image_start, KERNEL_SIZE);
        }
        
        /* Clear the zero page, then move the argument list in. */
index e3159d6..f3d9808 100644 (file)
@@ -100,3 +100,24 @@ halt:
        .prologue 0
        call_pal PAL_halt
        .end halt
+
+/* $16 - new stack page */
+       .align 3
+       .globl  move_stack
+       .ent    move_stack
+move_stack:
+       .prologue 0
+       lda     $0, 0x1fff($31)
+       and     $0, $30, $1                     /* Stack offset */
+       or      $1, $16, $16                    /* New stack pointer */
+       mov     $30, $1
+       mov     $16, $2
+1:     ldq     $3, 0($1)                       /* Move the stack */
+       addq    $1, 8, $1
+       stq     $3, 0($2)
+       and     $0, $1, $4
+       addq    $2, 8, $2
+       bne     $4, 1b
+       mov     $16, $30
+       ret     ($26)
+       .end move_stack
index b811950..1d65adf 100644 (file)
@@ -205,15 +205,3 @@ decompress_kernel(void *output_start,
 /*     puts(" done, booting the kernel.\n"); */
        return output_ptr;
 }
-
-/* dummy-up printk */
-asmlinkage int printk(const char *fmt, ...)
-{
-        va_list args;
-       long ret;
-
-        va_start(args, fmt);
-        ret = srm_printk(fmt, args);
-        va_end(args);
-       return ret;
-}
index ad654af..64ba449 100644 (file)
@@ -185,7 +185,7 @@ EXPORT_SYMBOL(cpu_data);
 EXPORT_SYMBOL(smp_num_cpus);
 EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_call_function_on_cpu);
-EXPORT_SYMBOL(atomic_dec_and_lock);
+EXPORT_SYMBOL(_atomic_dec_and_lock);
 #ifdef CONFIG_DEBUG_SPINLOCK
 EXPORT_SYMBOL(_raw_spin_unlock);
 EXPORT_SYMBOL(debug_spin_lock);
index 254ab65..cb3e739 100644 (file)
@@ -47,7 +47,7 @@ locate_and_init_vga(void *(*sel_func)(void *, void *))
 
        if (!sel_func) sel_func = (void *)default_vga_hose_select;
 
-       for(dev=NULL; (dev=pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, dev));) {
+       for(dev=NULL; (dev=pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, dev));) {
                if (!hose) hose = dev->sysdata;
                else hose = sel_func(hose, dev->sysdata);
        }
index b4c64d4..1f36bbd 100644 (file)
@@ -227,7 +227,7 @@ pdev_save_srm_config(struct pci_dev *dev)
        tmp->next = srm_saved_configs;
        tmp->dev = dev;
 
-       pci_save_state(dev, tmp->regs);
+       pci_save_state(dev);
 
        srm_saved_configs = tmp;
 }
@@ -243,7 +243,7 @@ pci_restore_srm_config(void)
 
        /* Restore SRM config. */
        for (tmp = srm_saved_configs; tmp; tmp = tmp->next) {
-               pci_restore_state(tmp->dev, tmp->regs);
+               pci_restore_state(tmp->dev);
        }
 }
 #endif
@@ -280,7 +280,6 @@ pcibios_fixup_bus(struct pci_bus *bus)
        /* Propagate hose info into the subordinate devices.  */
 
        struct pci_controller *hose = bus->sysdata;
-       struct list_head *ln;
        struct pci_dev *dev = bus->self;
 
        if (!dev) {
@@ -304,9 +303,7 @@ pcibios_fixup_bus(struct pci_bus *bus)
                pcibios_fixup_device_resources(dev, bus);
        } 
 
-       for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
-               struct pci_dev *dev = pci_dev_b(ln);
-
+       list_for_each_entry(dev, &bus->devices, bus_list) {
                pdev_save_srm_config(dev);
                if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
                        pcibios_fixup_device_resources(dev, bus);
@@ -403,11 +400,10 @@ pcibios_set_master(struct pci_dev *dev)
 static void __init
 pcibios_claim_one_bus(struct pci_bus *b)
 {
-       struct list_head *ld;
+       struct pci_dev *dev;
        struct pci_bus *child_bus;
 
-       for (ld = b->devices.next; ld != &b->devices; ld = ld->next) {
-               struct pci_dev *dev = pci_dev_b(ld);
+       list_for_each_entry(dev, &b->devices, bus_list) {
                int i;
 
                for (i = 0; i < PCI_NUM_RESOURCES; i++) {
@@ -426,12 +422,10 @@ pcibios_claim_one_bus(struct pci_bus *b)
 static void __init
 pcibios_claim_console_setup(void)
 {
-       struct list_head *lb;
+       struct pci_bus *b;
 
-       for(lb = pci_root_buses.next; lb != &pci_root_buses; lb = lb->next) {
-               struct pci_bus *b = pci_bus_b(lb);
+       list_for_each_entry(b, &pci_root_buses, node)
                pcibios_claim_one_bus(b);
-       }
 }
 
 void __init
index 54fb8f1..f8b7499 100644 (file)
@@ -166,7 +166,6 @@ struct pdev_srm_saved_conf
 {
        struct pdev_srm_saved_conf *next;
        struct pci_dev *dev;
-       u32 regs[16];
 };
 
 extern void pci_restore_srm_config(void);
index 49c8c97..6312402 100644 (file)
@@ -132,40 +132,11 @@ srmcons_do_write(struct tty_struct *tty, const char *buf, int count)
 }
 
 static int
-srmcons_write(struct tty_struct *tty, int from_user,
+srmcons_write(struct tty_struct *tty,
              const unsigned char *buf, int count)
 {
        unsigned long flags;
 
-       if (from_user) {
-               char tmp[512];
-               int ret = 0;
-               size_t c;
-
-               while ((c = count) > 0) {
-                       if (c > sizeof(tmp))
-                               c = sizeof(tmp);
-                       
-                       c -= copy_from_user(tmp, (const char __user *) buf, c);
-
-                       if (!c) { 
-                               printk("%s: EFAULT (count %d)\n",
-                                      __FUNCTION__, count);
-                               return -EFAULT;
-                       }
-
-                       spin_lock_irqsave(&srmcons_callback_lock, flags);
-                       srmcons_do_write(tty, tmp, c);
-                       spin_unlock_irqrestore(&srmcons_callback_lock, flags);
-
-                       buf += c;
-                       count -= c;
-                       ret += c;
-               }
-
-               return ret;
-       }
-
        spin_lock_irqsave(&srmcons_callback_lock, flags);
        srmcons_do_write(tty, (const char *) buf, count);
        spin_unlock_irqrestore(&srmcons_callback_lock, flags);
index 6852eee..145dcde 100644 (file)
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/reboot.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
index c3f9dbc..8e3374d 100644 (file)
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
index 32d9c35..61a79c3 100644 (file)
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
index 52873d5..8047278 100644 (file)
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
index a55c109..d78a0da 100644 (file)
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
index dd3bded..c0d696e 100644 (file)
 #include <linux/init.h>
 #include <linux/reboot.h>
 #include <linux/bootmem.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pci.h>
index 02363fa..65061f5 100644 (file)
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
index dfe16bc..5840424 100644 (file)
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
index 4466af6..147058f 100644 (file)
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
index 959e8d7..57be096 100644 (file)
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
index 5fc1303..6ae2500 100644 (file)
@@ -9,10 +9,10 @@
 #include <asm/atomic.h>
 
   asm (".text                                  \n\
-       .global atomic_dec_and_lock             \n\
-       .ent atomic_dec_and_lock                \n\
+       .global _atomic_dec_and_lock            \n\
+       .ent _atomic_dec_and_lock               \n\
        .align  4                               \n\
-atomic_dec_and_lock:                           \n\
+_atomic_dec_and_lock:                          \n\
        .prologue 0                             \n\
 1:     ldl_l   $1, 0($16)                      \n\
        subl    $1, 1, $1                       \n\
@@ -28,7 +28,7 @@ atomic_dec_and_lock:                          \n\
        .subsection 2                           \n\
 4:     br      1b                              \n\
        .previous                               \n\
-       .end atomic_dec_and_lock");
+       .end _atomic_dec_and_lock");
 
 static int __attribute_used__
 atomic_dec_and_lock_1(atomic_t *atomic, spinlock_t *lock)
index 266f46c..27542c0 100644 (file)
@@ -104,7 +104,7 @@ config DEBUG_S3C2410_PORT
          before it is used.
 
 config DEBUG_S3C2410_UART
-       depends on DEBUG_LL && ARCH_S3C2410
+       depends on ARCH_S3C2410
        int "S3C2410 UART to use for low-level debug"
        default "0"
        help
@@ -112,4 +112,7 @@ config DEBUG_S3C2410_UART
          should be between zero and two. The port must have been
          initalised by the boot-loader before use.
 
+         The uncompressor code port configuration is now handled
+         by CONFIG_S3C2410_LOWLEVEL_UART_PORT.
+
 endmenu
index f7ddb16..b5f5c6d 100644 (file)
@@ -194,7 +194,7 @@ amba_attr(resource, "\t%08lx\t%08lx\t%08lx\n",
 int amba_device_register(struct amba_device *dev, struct resource *parent)
 {
        u32 pid, cid;
-       void *tmp;
+       void __iomem *tmp;
        int i, ret;
 
        dev->dev.release = amba_device_release;
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);
index 46550dd..b86e288 100644 (file)
@@ -609,17 +609,15 @@ static void __locomo_remove(struct locomo *lchip)
 static int locomo_probe(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct resource *mem = NULL, *irq = NULL;
-       int i;
-
-       for (i = 0; i < pdev->num_resources; i++) {
-               if (pdev->resource[i].flags & IORESOURCE_MEM)
-                       mem = &pdev->resource[i];
-               if (pdev->resource[i].flags & IORESOURCE_IRQ)
-                       irq = &pdev->resource[i];
-       }
+       struct resource *mem;
+       int irq;
 
-       return __locomo_probe(dev, mem, irq ? irq->start : NO_IRQ);
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem)
+               return -EINVAL;
+       irq = platform_get_irq(pdev, 0);
+
+       return __locomo_probe(dev, mem, irq);
 }
 
 static int locomo_remove(struct device *dev)
@@ -629,9 +627,6 @@ static int locomo_remove(struct device *dev)
        if (lchip) {
                __locomo_remove(lchip);
                dev_set_drvdata(dev, NULL);
-
-               kfree(dev->saved_state);
-               dev->saved_state = NULL;
        }
 
        return 0;
@@ -756,7 +751,7 @@ module_exit(locomo_exit);
 
 MODULE_DESCRIPTION("Sharp LoCoMo core driver");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("John Lenz <jelenz@students.wisc.edu>");
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
 
 EXPORT_SYMBOL(locomo_driver_register);
 EXPORT_SYMBOL(locomo_driver_unregister);
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);
index eb06282..486add8 100644 (file)
@@ -15,6 +15,7 @@
  */
 #include <linux/timex.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -22,7 +23,7 @@
 
 #include <asm/mach/time.h>
 
-static unsigned long ioctime_gettimeoffset(void)
+unsigned long ioc_timer_gettimeoffset(void)
 {
        unsigned int count1, count2, status;
        long offset;
@@ -62,6 +63,34 @@ void __init ioctime_init(void)
        ioc_writeb(LATCH & 255, IOC_T0LTCHL);
        ioc_writeb(LATCH >> 8, IOC_T0LTCHH);
        ioc_writeb(0, IOC_T0GO);
+}
+
+static irqreturn_t
+ioc_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 ioc_timer_irq = {
+       .name           = "timer",
+       .flags          = SA_INTERRUPT,
+       .handler        = ioc_timer_interrupt
+};
 
-       gettimeoffset = ioctime_gettimeoffset;
+/*
+ * Set up timer interrupt.
+ */
+static void __init ioc_timer_init(void)
+{
+       ioctime_init();
+       setup_irq(IRQ_TIMER, &ioc_timer_irq);
 }
+
+struct sys_timer ioc_timer = {
+       .init           = ioc_timer_init,
+       .offset         = ioc_timer_gettimeoffset,
+};
+
index 45deb45..dc986ca 100644 (file)
@@ -1,31 +1,35 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc2
+# Mon Nov 15 15:32:48 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 is not set
-CONFIG_STANDALONE=y
 CONFIG_BROKEN=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=17
+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
@@ -33,11 +37,13 @@ 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
+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
@@ -46,6 +52,7 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
@@ -60,6 +67,7 @@ CONFIG_KMOD=y
 # 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
@@ -68,15 +76,28 @@ CONFIG_ARCH_S3C2410=y
 # 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_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
-# S3C2410 Implementations
+# S3C24XX Implementations
 #
 CONFIG_ARCH_BAST=y
 # CONFIG_ARCH_H1940 is not set
 # CONFIG_ARCH_SMDK2410 is not set
 CONFIG_MACH_VR1000=y
+# CONFIG_MACH_RX3715 is not set
+CONFIG_CPU_S3C2410=y
+
+#
+# S3C2410 Setup
+#
+CONFIG_S3C2410_DMA=y
+# CONFIG_S3C2410_DMA_DEBUG is not set
+# CONFIG_S3C2410_PM_DEBUG is not set
+# CONFIG_S3C2410_PM_CHECK is not set
+CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
 
 #
 # Processor Type
@@ -86,6 +107,7 @@ CONFIG_CPU_ARM920T=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4T=y
 CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
 
@@ -103,14 +125,14 @@ CONFIG_CPU_TLB_V4WBI=y
 # CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_XIP_KERNEL is not set
 
 #
 # At least one math emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
-CONFIG_FPE_NWFPE_XP=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
@@ -118,13 +140,13 @@ CONFIG_BINFMT_AOUT=y
 #
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_DEBUG_DRIVER is not set
-# CONFIG_PM is not set
+CONFIG_PM=y
 # CONFIG_PREEMPT is not set
+CONFIG_APM=y
 # CONFIG_ARTHUR is not set
-CONFIG_S3C2410_DMA=y
-# CONFIG_S3C2410_DMA_DEBUG is not set
 CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -132,10 +154,7 @@ CONFIG_ALIGNMENT_TRAP=y
 # Parallel port support
 #
 CONFIG_PARPORT=y
-CONFIG_PARPORT_PC=y
-CONFIG_PARPORT_PC_CML1=y
-CONFIG_PARPORT_PC_FIFO=y
-CONFIG_PARPORT_PC_SUPERIO=y
+# CONFIG_PARPORT_PC is not set
 # CONFIG_PARPORT_ARC is not set
 CONFIG_PARPORT_OTHER=y
 CONFIG_PARPORT_1284=y
@@ -145,8 +164,13 @@ CONFIG_PARPORT_1284=y
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_PARTITIONS 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 is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
 
 #
 # User Modules And Translation Layers
@@ -161,12 +185,23 @@ CONFIG_MTD_BLOCK=y
 # RAM/ROM/Flash chip drivers
 #
 CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_JEDECPROBE=y
 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=y
+# 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
@@ -179,11 +214,15 @@ CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_IMPA7 is not set
+CONFIG_MTD_BAST=y
+CONFIG_MTD_BAST_MAXSIZE=4
 
 #
 # 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
 
@@ -197,7 +236,13 @@ CONFIG_MTD_CFI_INTELEXT=y
 #
 # NAND Flash Device Drivers
 #
-# CONFIG_MTD_NAND is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_S3C2410=y
+# CONFIG_MTD_NAND_S3C2410_DEBUG is not set
+# CONFIG_MTD_NAND_S3C2410_HWECC is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
 
 #
 # Plug and Play support
@@ -214,6 +259,16 @@ CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # Multi-device support (RAID and LVM)
@@ -246,6 +301,9 @@ CONFIG_IP_PNP_BOOTP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -265,7 +323,6 @@ CONFIG_IP_PNP_BOOTP=y
 # 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
@@ -338,13 +395,13 @@ CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=m
 # 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_IDE_BAST=y
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -395,16 +452,16 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # 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_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_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
@@ -431,8 +488,6 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_DIGI is not set
 # CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
-# CONFIG_ISI is not set
-# CONFIG_SYNCLINK is not set
 # CONFIG_SYNCLINKMP is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
@@ -459,7 +514,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 #
 CONFIG_SERIAL_S3C2410=y
 CONFIG_SERIAL_S3C2410_CONSOLE=y
-# CONFIG_SERIAL_BAST_SIO is not set
+CONFIG_SERIAL_BAST_SIO=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -469,7 +524,6 @@ CONFIG_PRINTER=y
 # CONFIG_LP_CONSOLE is not set
 CONFIG_PPDEV=y
 # CONFIG_TIPAR is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -479,18 +533,23 @@ CONFIG_PPDEV=y
 #
 # Watchdog Cards
 #
-# CONFIG_WATCHDOG is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_S3C2410_WATCHDOG=y
 # CONFIG_NVRAM is not set
-CONFIG_RTC=y
+# CONFIG_RTC is not set
+CONFIG_S3C2410_RTC=y
 # 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
 
@@ -505,35 +564,42 @@ CONFIG_I2C_CHARDEV=m
 #
 CONFIG_I2C_ALGOBIT=m
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_SCx200_ACB is not set
+CONFIG_I2C_S3C2410=y
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
 #
 CONFIG_I2C_SENSOR=m
 # 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_LM63 is not set
 CONFIG_SENSORS_LM75=m
+# CONFIG_SENSORS_LM77 is not set
 CONFIG_SENSORS_LM78=m
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 CONFIG_SENSORS_LM85=m
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
@@ -578,6 +644,7 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -621,9 +688,14 @@ CONFIG_RAMFS=y
 # CONFIG_EFS_FS is not set
 CONFIG_JFFS_FS=y
 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 is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -644,6 +716,7 @@ CONFIG_LOCKD=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
@@ -654,13 +727,7 @@ CONFIG_SUNRPC=y
 # Partition Types
 #
 CONFIG_PARTITION_ADVANCED=y
-CONFIG_ACORN_PARTITION=y
-CONFIG_ACORN_PARTITION_CUMANA=y
-CONFIG_ACORN_PARTITION_EESOX=y
-CONFIG_ACORN_PARTITION_ICS=y
-CONFIG_ACORN_PARTITION_ADFS=y
-CONFIG_ACORN_PARTITION_POWERTEC=y
-CONFIG_ACORN_PARTITION_RISCIX=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
@@ -729,13 +796,14 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE is not set
 
@@ -756,24 +824,34 @@ CONFIG_DUMMY_CONSOLE=y
 #
 # USB support
 #
+# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC 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 is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_KOBJECT 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=y
 # CONFIG_DEBUG_ICEDCC is not set
@@ -783,6 +861,7 @@ CONFIG_DEBUG_S3C2410_UART=0
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index fc4dbc2..e2c9926 100644 (file)
@@ -1,10 +1,13 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3
+# Wed Dec 15 17:03:41 2004
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +19,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -25,17 +29,20 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_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
+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
@@ -45,6 +52,7 @@ 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
 
 #
@@ -59,6 +67,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_INTEGRATOR is not set
 CONFIG_ARCH_IOP3XX=y
 # 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
@@ -67,7 +76,9 @@ CONFIG_ARCH_IOP3XX=y
 # 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_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # IOP3xx Implementation Options
@@ -94,6 +105,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -110,6 +122,7 @@ CONFIG_PCI=y
 # CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_XIP_KERNEL is not set
 # CONFIG_PCI_LEGACY_PROC is not set
 CONFIG_PCI_NAMES=y
 
@@ -119,7 +132,6 @@ CONFIG_PCI_NAMES=y
 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
@@ -148,8 +160,8 @@ CONFIG_MTD=y
 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_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -191,7 +203,10 @@ CONFIG_MTD_CFI_UTIL=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xf0000000
+CONFIG_MTD_PHYSMAP_LEN=0x00800000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_EDB7312 is not set
 
@@ -232,8 +247,19 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 # 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=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # Multi-device support (RAID and LVM)
@@ -243,9 +269,11 @@ CONFIG_BLK_DEV_MD=y
 # CONFIG_MD_LINEAR is not set
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
+# CONFIG_MD_RAID10 is not set
 CONFIG_MD_RAID5=y
 # CONFIG_MD_RAID6 is not set
 # CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
 CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_CRYPT is not set
 # CONFIG_DM_SNAPSHOT is not set
@@ -280,6 +308,9 @@ CONFIG_IP_PNP_BOOTP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -299,7 +330,6 @@ CONFIG_IP_PNP_BOOTP=y
 # 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
@@ -362,7 +392,6 @@ CONFIG_E100_NAPI=y
 # 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)
@@ -375,6 +404,7 @@ CONFIG_E100_NAPI=y
 # 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
 
 #
@@ -449,7 +479,8 @@ CONFIG_CHR_DEV_SG=y
 # 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_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
@@ -458,6 +489,7 @@ CONFIG_CHR_DEV_SG=y
 # 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
@@ -519,7 +551,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
 
 #
 # Input Device Drivers
@@ -554,7 +585,6 @@ 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
@@ -567,7 +597,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # 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
@@ -575,7 +604,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -590,6 +618,7 @@ CONFIG_I2C_CHARDEV=y
 #
 # CONFIG_I2C_ALGOBIT is not set
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
@@ -612,9 +641,11 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
@@ -622,20 +653,25 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_I2C_SENSOR is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 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_LM63 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_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 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
@@ -685,6 +721,7 @@ CONFIG_XFS_POSIX_ACL=y
 # 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
 
@@ -709,6 +746,7 @@ 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
 
@@ -754,6 +792,7 @@ 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 is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -799,7 +838,6 @@ CONFIG_MSDOS_PARTITION=y
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 
 #
@@ -815,23 +853,35 @@ CONFIG_DUMMY_CONSOLE=y
 # USB support
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
 #
 # Kernel hacking
 #
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_INFO is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_KERNEL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index 8e24132..5efaeef 100644 (file)
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3
+# Mon Dec 20 16:08:21 2004
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+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 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=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_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 is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 CONFIG_ARCH_INTEGRATOR=y
+# 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 is not set
-# CONFIG_ARCH_CLPS711X is not set
-
-#
-# Archimedes/A5000 Implementations
-#
+# 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 is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
-# Archimedes/A5000 Implementations (select only ONE)
+# Integrator Options
 #
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-
-#
-# Footbridge Implementations
-#
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
-
-#
-# SA11x0 Implementations
-#
-# CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_BRUTUS is not set
-# CONFIG_SA1100_CERF is not set
-# CONFIG_SA1100_BITSY is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_JORNADA720 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_SHERMAN is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
+CONFIG_ARCH_INTEGRATOR_AP=y
+# CONFIG_ARCH_INTEGRATOR_CP is not set
+# CONFIG_INTEGRATOR_IMPD1 is not set
 
 #
 # Processor Type
 #
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
+CONFIG_CPU_32=y
 CONFIG_CPU_ARM720T=y
 CONFIG_CPU_ARM920T=y
-CONFIG_CPU_ARM920_CPU_IDLE=y
-CONFIG_CPU_ARM920_I_CACHE_ON=y
-CONFIG_CPU_ARM920_D_CACHE_ON=y
-# CONFIG_CPU_ARM920_WRITETHROUGH is not set
+# CONFIG_CPU_ARM926T is not set
 # CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
-# CONFIG_CPU_SA1100 is not set
-# CONFIG_DISCONTIGMEM is not set
+# CONFIG_CPU_ARM1022 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_V6 is not set
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_ABRT_LV4T=y
+CONFIG_CPU_CACHE_V4=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WT=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 
 #
 # General setup
 #
-CONFIG_PCI_INTEGRATOR=y
 CONFIG_PCI=y
-# CONFIG_ISA is not set
-# CONFIG_ISA_DMA is not set
-CONFIG_CPU_CLOCK=y
+CONFIG_ICST525=y
+CONFIG_ARM_AMBA=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_XIP_KERNEL is not set
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_PROC_INTF is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_24_API is not set
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_INTEGRATOR=y
+CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_FPE_NWFPE is not set
-CONFIG_FPE_FASTFPE=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=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 is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
 CONFIG_PM=y
+# CONFIG_PREEMPT is not set
+# CONFIG_APM is not set
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="root=1f03 mem=32M"
+CONFIG_CMDLINE="console=ttyAM0,38400n8 root=/dev/nfs ip=bootp mem=32M"
 CONFIG_LEDS=y
 CONFIG_LEDS_TIMER=y
 CONFIG_LEDS_CPU=y
@@ -150,8 +178,9 @@ CONFIG_ALIGNMENT_TRAP=y
 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_BOOTLDR_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_AFS_PARTS=y
 
 #
@@ -161,259 +190,264 @@ 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_CFI_VIRTUAL_ER is not set
+# 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_LART_BIT_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_AMDSTD is not set
-# CONFIG_MTD_SHARP 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_JEDEC 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_SUN_UFLASH is not set
-# CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_NETSC520 is not set
-# CONFIG_MTD_SBC_GXX is not set
-# CONFIG_MTD_ELAN_104NC is not set
-# CONFIG_MTD_SA1100 is not set
-# CONFIG_MTD_SA1100_REDBOOT_PARTITIONS is not set
-# CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_DBOX2 is not set
-# CONFIG_MTD_CSTM_MIPS_IXX is not set
-# CONFIG_MTD_CFI_FLAGADM is not set
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_VMAX is not set
-CONFIG_MTD_ARMFLASH=y
+# 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_DOC1000 is not set
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
 #
 # CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_SPIA is not set
 
 #
-# Plug and Play configuration
+# Plug and Play support
 #
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE 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_LOOP 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=4096
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER 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_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_IP_MROUTE is not set
-CONFIG_INET_ECN=y
+# 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_KHTTPD is not set
-# CONFIG_ATM 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_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC 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 device support
+# 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
-# 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
-# CONFIG_NET_SB1000 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_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_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP 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_APRICOT is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_TULIP is not set
-# CONFIG_DE4X5 is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
-# CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
-CONFIG_EEPRO100_PM=y
-# CONFIG_LNE390 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_NE3210 is not set
-# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
 # CONFIG_8139TOO is not set
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 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_WINBOND_840 is not set
-# CONFIG_HAPPYMEAL 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_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Ethernet (10000 Mbit)
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
 
 #
 # Token Ring devices
 #
 # CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
 
 #
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_NET_RADIO is not set
 
 #
-# IrDA (infrared) support
+# Wan interfaces
 #
-# CONFIG_IRDA is not set
+# 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
 
 #
-# ATA/IDE/MFM/RLL support
+# SCSI device support
 #
-# CONFIG_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_SCSI is not set
 
 #
-# SCSI support
+# Fusion MPT device support
 #
-# CONFIG_SCSI is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -424,11 +458,6 @@ CONFIG_EEPRO100_PM=y
 # I2O device support
 #
 # CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
 
 #
 # ISDN subsystem
@@ -436,62 +465,85 @@ CONFIG_EEPRO100_PM=y
 # CONFIG_ISDN is not set
 
 #
-# Input core support
+# 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_INPUT is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_AMBAKMI 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 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=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_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-# CONFIG_SERIAL_SA1100 is not set
-# CONFIG_SERIAL_SA1100_CONSOLE is not set
-CONFIG_SERIAL_AMBA=y
-CONFIG_SERIAL_AMBA_CONSOLE=y
-CONFIG_SERIAL_INTEGRATOR=y
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
 
 #
-# I2C support
+# Serial drivers
 #
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
-# Joysticks
+# Non-8250 serial port support
 #
-# CONFIG_JOYSTICK is not set
+CONFIG_SERIAL_AMBA_PL010=y
+CONFIG_SERIAL_AMBA_PL010_CONSOLE=y
+# CONFIG_SERIAL_AMBA_PL011 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
-# Input core support is needed for joysticks
+# IPMI
 #
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -501,85 +553,114 @@ CONFIG_PSMOUSE=y
 #
 # 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=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_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK 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_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW 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_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_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_CRAMFS is not set
-# CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-CONFIG_MINIX_FS=y
+# 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=y
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-CONFIG_ROMFS_FS=y
-CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
-# CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=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 is not set
+# CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
-# 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 is not set
-# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
@@ -590,71 +671,134 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_AMIGA_PARTITION is not set
 # CONFIG_ATARI_PARTITION is not set
 # CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_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_SMB_NLS is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
 # CONFIG_NLS is not set
 
 #
-# Console drivers
+# Profiling support
 #
-CONFIG_KMI_KEYB=y
-CONFIG_KMI_MOUSE=y
-CONFIG_PC_KEYMAP=y
-CONFIG_VGA_CONSOLE=y
-CONFIG_FB=y
+# CONFIG_PROFILING is not set
 
 #
-# Frame-buffer support
+# Graphics support
 #
 CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_CLGEN is not set
+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_ACORN is not set
-# CONFIG_FB_CLPS711X is not set
+# CONFIG_FB_ARMCLCD is not set
 # CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_SA1100 is not set
-# CONFIG_FB_E1355 is not set
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_ATY is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_RIVA is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G450=y
+CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_MULTIHEAD=y
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
-# CONFIG_FB_3DFX 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_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-CONFIG_FBCON_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+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
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
 
 #
 # Kernel hacking
 #
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
 CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_NO_PGT_CACHE is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
+# CONFIG_DEBUG_LL 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
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
index 64ebb89..89c0eb2 100644 (file)
@@ -1,10 +1,13 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3
+# Wed Dec 15 16:58:36 2004
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +19,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -25,17 +29,20 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_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
+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
@@ -45,6 +52,7 @@ 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
 
 #
@@ -59,6 +67,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_INTEGRATOR is not set
 CONFIG_ARCH_IOP3XX=y
 # 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
@@ -67,7 +76,9 @@ CONFIG_ARCH_IOP3XX=y
 # 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_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # IOP3xx Implementation Options
@@ -94,6 +105,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -110,6 +122,7 @@ CONFIG_PCI=y
 # CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_XIP_KERNEL is not set
 # CONFIG_PCI_LEGACY_PROC is not set
 CONFIG_PCI_NAMES=y
 
@@ -119,7 +132,6 @@ CONFIG_PCI_NAMES=y
 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
@@ -148,8 +160,8 @@ CONFIG_MTD=y
 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_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -191,7 +203,10 @@ CONFIG_MTD_CFI_UTIL=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xf0000000
+CONFIG_MTD_PHYSMAP_LEN=0x00800000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_EDB7312 is not set
 
@@ -232,8 +247,19 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 # 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=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # Multi-device support (RAID and LVM)
@@ -243,9 +269,11 @@ CONFIG_BLK_DEV_MD=y
 # CONFIG_MD_LINEAR is not set
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
+# CONFIG_MD_RAID10 is not set
 CONFIG_MD_RAID5=y
 # CONFIG_MD_RAID6 is not set
 # CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
 CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_CRYPT is not set
 # CONFIG_DM_SNAPSHOT is not set
@@ -280,6 +308,9 @@ CONFIG_IP_PNP_BOOTP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -299,7 +330,6 @@ CONFIG_IP_PNP_BOOTP=y
 # 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
@@ -418,7 +448,8 @@ CONFIG_CHR_DEV_SG=y
 # 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_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
@@ -427,6 +458,7 @@ CONFIG_CHR_DEV_SG=y
 # 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
@@ -488,7 +520,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
 
 #
 # Input Device Drivers
@@ -523,7 +554,6 @@ 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
@@ -536,7 +566,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # 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
@@ -544,7 +573,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -559,6 +587,7 @@ CONFIG_I2C_CHARDEV=y
 #
 # CONFIG_I2C_ALGOBIT is not set
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
@@ -581,9 +610,11 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
@@ -591,20 +622,25 @@ CONFIG_I2C_IOP3XX=y
 # CONFIG_I2C_SENSOR is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 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_LM63 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_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 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
@@ -654,6 +690,7 @@ CONFIG_XFS_POSIX_ACL=y
 # 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
 
@@ -678,6 +715,7 @@ 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
 
@@ -723,6 +761,7 @@ 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 is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -768,7 +807,6 @@ CONFIG_MSDOS_PARTITION=y
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 
 #
@@ -784,23 +822,35 @@ CONFIG_DUMMY_CONSOLE=y
 # USB support
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
 #
 # Kernel hacking
 #
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_INFO is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_KERNEL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index f19320b..f3e0818 100644 (file)
@@ -1,10 +1,13 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3
+# Wed Dec 15 16:48:43 2004
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +19,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -25,17 +29,20 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_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
+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
@@ -45,6 +52,7 @@ 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
 
 #
@@ -59,6 +67,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_INTEGRATOR is not set
 CONFIG_ARCH_IOP3XX=y
 # 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
@@ -67,7 +76,9 @@ CONFIG_ARCH_IOP3XX=y
 # 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_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # IOP3xx Implementation Options
@@ -94,6 +105,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -110,6 +122,7 @@ CONFIG_PCI=y
 # CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_XIP_KERNEL is not set
 # CONFIG_PCI_LEGACY_PROC is not set
 CONFIG_PCI_NAMES=y
 
@@ -119,7 +132,6 @@ CONFIG_PCI_NAMES=y
 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
@@ -148,8 +160,8 @@ CONFIG_MTD=y
 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_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -191,7 +203,10 @@ CONFIG_MTD_CFI_UTIL=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xf0000000
+CONFIG_MTD_PHYSMAP_LEN=0x00800000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_EDB7312 is not set
 
@@ -232,8 +247,19 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 # 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=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # Multi-device support (RAID and LVM)
@@ -268,6 +294,9 @@ CONFIG_IP_PNP_BOOTP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -287,7 +316,6 @@ CONFIG_IP_PNP_BOOTP=y
 # 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
@@ -413,7 +441,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
 
 #
 # Input Device Drivers
@@ -448,7 +475,6 @@ 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
@@ -461,7 +487,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # 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
@@ -469,7 +494,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -510,6 +534,7 @@ CONFIG_XFS_POSIX_ACL=y
 # 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
 
@@ -534,6 +559,7 @@ 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
 
@@ -579,6 +605,7 @@ 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 is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -624,7 +651,6 @@ CONFIG_MSDOS_PARTITION=y
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 
 #
@@ -640,23 +666,35 @@ CONFIG_DUMMY_CONSOLE=y
 # USB support
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
 #
 # Kernel hacking
 #
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_INFO is not set
 CONFIG_FRAME_POINTER=y
 # CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_KERNEL is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index 9adbf9b..b744add 100644 (file)
@@ -1,10 +1,13 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3
+# Wed Dec 15 16:43:39 2004
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -16,6 +19,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -25,6 +29,7 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
@@ -32,11 +37,13 @@ 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
+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
@@ -46,6 +53,7 @@ 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
 
 #
@@ -60,6 +68,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_INTEGRATOR is not set
 CONFIG_ARCH_IOP3XX=y
 # 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
@@ -68,7 +77,9 @@ CONFIG_ARCH_IOP3XX=y
 # 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_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # IOP3xx Implementation Options
@@ -94,6 +105,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_XSCALE=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
 CONFIG_CPU_MINICACHE=y
 
@@ -110,6 +122,7 @@ CONFIG_PCI=y
 # CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_XIP_KERNEL is not set
 # CONFIG_PCI_LEGACY_PROC is not set
 CONFIG_PCI_NAMES=y
 
@@ -119,7 +132,6 @@ CONFIG_PCI_NAMES=y
 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
@@ -149,8 +161,8 @@ CONFIG_MTD=y
 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_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -196,7 +208,10 @@ CONFIG_MTD_CFI_UTIL=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xc0000000
+CONFIG_MTD_PHYSMAP_LEN=0x00800000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_EDB7312 is not set
 
@@ -237,8 +252,19 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 # 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=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # Multi-device support (RAID and LVM)
@@ -248,9 +274,11 @@ CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
+# CONFIG_MD_RAID10 is not set
 CONFIG_MD_RAID5=y
 # CONFIG_MD_RAID6 is not set
 # CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
 CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_CRYPT is not set
 # CONFIG_DM_SNAPSHOT is not set
@@ -285,6 +313,9 @@ CONFIG_IP_PNP_BOOTP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -304,7 +335,6 @@ CONFIG_IP_PNP_BOOTP=y
 # 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
@@ -423,7 +453,8 @@ CONFIG_CHR_DEV_SG=y
 # 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_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
@@ -432,6 +463,7 @@ CONFIG_CHR_DEV_SG=y
 # 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
@@ -493,7 +525,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
 
 #
 # Input Device Drivers
@@ -528,7 +559,6 @@ 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
@@ -541,7 +571,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # 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
@@ -549,7 +578,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -590,6 +618,7 @@ CONFIG_XFS_POSIX_ACL=y
 # 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
 
@@ -614,6 +643,7 @@ 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
 
@@ -653,6 +683,7 @@ 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 is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -698,7 +729,6 @@ CONFIG_MSDOS_PARTITION=y
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 
 #
@@ -714,30 +744,44 @@ CONFIG_DUMMY_CONSOLE=y
 # USB support
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 
 #
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
 #
 # 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_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_KOBJECT 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 is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index d9389a2..ca2cb5a 100644 (file)
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc2
+# Wed Nov 24 15:12:32 2004
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SHMEM is not set
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_TINY_SHMEM=y
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_L7200 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_CLPS711X is not set
-
-#
-# Archimedes/A5000 Implementations
-#
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-
-#
-# Footbridge Implementations
-#
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER 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 is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
-# CONFIG_SA1100_BITSY 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_COLLIE is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_HACKKIT 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=y
-# CONFIG_SA1100_SHERMAN is not set
-# 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_SHANNON is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SSP is not set
 # CONFIG_SA1100_USB is not set
-# CONFIG_SA1100_USB_NETLINK is not set
-# CONFIG_SA1100_USB_CHAR is not set
 
 #
-# CLPS711X/EP721X Implementations
+# Processor Type
 #
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
 CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
 CONFIG_CPU_SA1100=y
-CONFIG_DISCONTIGMEM=y
-# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
 
 #
 # General setup
 #
-# CONFIG_PCI is not set
-# CONFIG_ISA is not set
-# CONFIG_ISA_DMA is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_ISA=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_XIP_KERNEL is not set
 CONFIG_CPU_FREQ=y
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_PROC_INTF is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_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_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
 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_APM is not set
+# CONFIG_PREEMPT is not set
 # CONFIG_ARTHUR is not set
 CONFIG_CMDLINE="console=ttySA0,9600 mem=16M@0xc0000000 mem=16M@0xc8000000 root=/dev/ram initrd=0xc0400000,4M"
-# CONFIG_PFS168_CMDLINE is not set
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -138,56 +165,73 @@ CONFIG_ALIGNMENT_TRAP=y
 #
 # Memory Technology Devices (MTD)
 #
-# CONFIG_MTD is not set
+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 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 is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
+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_AMDSTD is not set
-# CONFIG_MTD_SHARP 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_JEDEC 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_SUN_UFLASH is not set
-# CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_NETSC520 is not set
-# CONFIG_MTD_SBC_GXX is not set
-# CONFIG_MTD_ELAN_104NC is not set
-# CONFIG_MTD_SA1100 is not set
-# CONFIG_MTD_SA1100_REDBOOT_PARTITIONS is not set
-# CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_DBOX2 is not set
-# CONFIG_MTD_CSTM_MIPS_IXX is not set
-# CONFIG_MTD_CFI_FLAGADM is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_VMAX is not set
-# CONFIG_MTD_OCELOT is not set
+CONFIG_MTD_SA1100=y
+# 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_DOC1000 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_DOCPROBE is not set
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -195,155 +239,175 @@ CONFIG_ALIGNMENT_TRAP=y
 # CONFIG_MTD_NAND is not set
 
 #
-# Plug and Play configuration
+# Plug and Play support
 #
 # CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE 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_LOOP 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=8192
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 
 #
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
-CONFIG_PACKET=m
+CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER 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 is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-CONFIG_INET_ECN=y
+# 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_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
-# CONFIG_KHTTPD 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_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC 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 device support
+# 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
-CONFIG_DUMMY=m
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
-# CONFIG_NET_ETHERNET is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# 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)
 #
-# CONFIG_ACENIC is not set
-# CONFIG_ACENIC_OMIT_TIGON_I is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Ethernet (10000 Mbit)
 #
-# CONFIG_NET_RADIO is not set
 
 #
 # Token Ring devices
 #
 # CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER 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
 
 #
-# Amateur Radio support
+# ATA/ATAPI/MFM/RLL support
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_IDE is not set
 
 #
-# IrDA (infrared) support
+# SCSI device support
 #
-# CONFIG_IRDA is not set
+# CONFIG_SCSI is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Fusion MPT device support
 #
-# CONFIG_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI support
+# IEEE 1394 (FireWire) support
 #
-# CONFIG_SCSI is not set
 
 #
 # I2O device support
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
 
 #
 # ISDN subsystem
@@ -351,183 +415,285 @@ CONFIG_DUMMY=m
 # CONFIG_ISDN is not set
 
 #
-# Input core support
+# 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
+
+#
+# Input Device Drivers
+#
+
 #
 # Character devices
 #
 # CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-CONFIG_SERIAL_SA1100=y
-# CONFIG_SERIAL_SA1100_OLD is not set
-CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_SA1100_DEFAULT_BAUDRATE=9600
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_UCB1200 is not set
-# CONFIG_TOUCHSCREEN_UCB1200 is not set
-# CONFIG_AUDIO_UCB1200 is not set
-# CONFIG_ADC_UCB1200 is not set
-# CONFIG_TOUCHSCREEN_BITSY is not set
-CONFIG_PROFILER=y
-# CONFIG_PFS168_SPI is not set
-# CONFIG_PFS168_DTMF is not set
-# CONFIG_PFS168_MISC is not set
 
 #
-# I2C support
+# Serial drivers
 #
-# CONFIG_I2C is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
-# Mice
+# Non-8250 serial port support
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
+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
 
 #
-# Joysticks
+# IPMI
 #
-# CONFIG_JOYSTICK is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-CONFIG_SA1100_RTC=y
 # 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=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_DNOTIFY is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK 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 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_ADFS_FS_RW 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_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_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_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
-# CONFIG_CODA_FS is not set
-# CONFIG_NFS_FS is not set
-# CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+CONFIG_NFS_DIRECTIO=y
 # CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-# CONFIG_SUNRPC is not set
-# CONFIG_LOCKD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=m
+# 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_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 is not set
-# CONFIG_NCPFS_EXTRAS 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
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS 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
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
-# Bluetooth support
+# USB Gadget Support
 #
-# CONFIG_BT is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
 
 #
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_NO_PGT_CACHE is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL 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
index 9919e7f..907ec6a 100644 (file)
@@ -1,10 +1,13 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc2
+# Mon Nov 15 15:29:42 2004
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -17,6 +20,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -25,6 +29,7 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 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
@@ -32,11 +37,13 @@ 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
+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
@@ -45,6 +52,7 @@ CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 #
@@ -59,6 +67,7 @@ CONFIG_KMOD=y
 # 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
@@ -67,21 +76,29 @@ CONFIG_ARCH_S3C2410=y
 # 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_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
 
 #
-# S3C2410 Implementations
+# S3C24XX Implementations
 #
 CONFIG_ARCH_BAST=y
 CONFIG_ARCH_H1940=y
 CONFIG_ARCH_SMDK2410=y
 CONFIG_MACH_VR1000=y
+CONFIG_MACH_RX3715=y
+CONFIG_CPU_S3C2410=y
+CONFIG_CPU_S3C2440=y
 
 #
 # S3C2410 Setup
 #
 CONFIG_S3C2410_DMA=y
 # CONFIG_S3C2410_DMA_DEBUG is not set
+# CONFIG_S3C2410_PM_DEBUG is not set
+# CONFIG_S3C2410_PM_CHECK is not set
+CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
 
 #
 # Processor Type
@@ -91,6 +108,7 @@ CONFIG_CPU_ARM920T=y
 CONFIG_CPU_32v4=y
 CONFIG_CPU_ABRT_EV4T=y
 CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
 
@@ -108,14 +126,14 @@ CONFIG_CPU_TLB_V4WBI=y
 # CONFIG_ZBOOT_ROM is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_XIP_KERNEL is not set
 
 #
 # At least one math emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
-CONFIG_FPE_NWFPE_XP=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
@@ -126,8 +144,9 @@ CONFIG_BINFMT_AOUT=y
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_DEBUG_DRIVER is not set
-# CONFIG_PM is not set
+CONFIG_PM=y
 # CONFIG_PREEMPT is not set
+CONFIG_APM=y
 # CONFIG_ARTHUR is not set
 CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
 CONFIG_ALIGNMENT_TRAP=y
@@ -136,10 +155,7 @@ CONFIG_ALIGNMENT_TRAP=y
 # Parallel port support
 #
 CONFIG_PARPORT=y
-CONFIG_PARPORT_PC=y
-CONFIG_PARPORT_PC_CML1=y
-CONFIG_PARPORT_PC_FIFO=y
-CONFIG_PARPORT_PC_SUPERIO=y
+# CONFIG_PARPORT_PC is not set
 # CONFIG_PARPORT_ARC is not set
 CONFIG_PARPORT_OTHER=y
 CONFIG_PARPORT_1284=y
@@ -149,8 +165,13 @@ CONFIG_PARPORT_1284=y
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_PARTITIONS 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 is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
 
 #
 # User Modules And Translation Layers
@@ -165,14 +186,14 @@ CONFIG_MTD_BLOCK=y
 # RAM/ROM/Flash chip drivers
 #
 CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_JEDECPROBE=y
 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_16=y
 # CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
 CONFIG_MTD_CFI_I1=y
 CONFIG_MTD_CFI_I2=y
@@ -194,6 +215,9 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_IMPA7 is not set
+CONFIG_MTD_BAST=y
+CONFIG_MTD_BAST_MAXSIZE=4
 
 #
 # Self-contained MTD device drivers
@@ -213,7 +237,13 @@ CONFIG_MTD_CFI_UTIL=y
 #
 # NAND Flash Device Drivers
 #
-# CONFIG_MTD_NAND is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_S3C2410=y
+# CONFIG_MTD_NAND_S3C2410_DEBUG is not set
+# CONFIG_MTD_NAND_S3C2410_HWECC is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
 
 #
 # Plug and Play support
@@ -230,6 +260,16 @@ CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # Multi-device support (RAID and LVM)
@@ -262,6 +302,9 @@ CONFIG_IP_PNP_BOOTP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -281,7 +324,6 @@ CONFIG_IP_PNP_BOOTP=y
 # 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
@@ -354,13 +396,13 @@ CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=m
 # 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_IDE_BAST=y
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -411,10 +453,10 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # 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_PARKBD is not set
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -483,7 +525,6 @@ CONFIG_PRINTER=y
 # CONFIG_LP_CONSOLE is not set
 CONFIG_PPDEV=y
 # CONFIG_TIPAR is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -493,16 +534,23 @@ CONFIG_PPDEV=y
 #
 # Watchdog Cards
 #
-# CONFIG_WATCHDOG is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_S3C2410_WATCHDOG=y
 # CONFIG_NVRAM is not set
-CONFIG_RTC=y
+# CONFIG_RTC is not set
+CONFIG_S3C2410_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
 
@@ -517,16 +565,17 @@ CONFIG_I2C_CHARDEV=m
 #
 CONFIG_I2C_ALGOBIT=m
 # CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
 
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_SCx200_ACB is not set
+CONFIG_I2C_S3C2410=y
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Hardware Sensors Chip support
@@ -540,14 +589,18 @@ CONFIG_I2C_SENSOR=m
 # CONFIG_SENSORS_FSCHER is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
 CONFIG_SENSORS_LM75=m
 # CONFIG_SENSORS_LM77 is not set
 CONFIG_SENSORS_LM78=m
 # CONFIG_SENSORS_LM80 is not set
 # CONFIG_SENSORS_LM83 is not set
 CONFIG_SENSORS_LM85=m
+# CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
@@ -592,6 +645,7 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -663,6 +717,7 @@ CONFIG_LOCKD=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
@@ -742,13 +797,14 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE is not set
 
@@ -769,24 +825,34 @@ CONFIG_DUMMY_CONSOLE=y
 #
 # USB support
 #
+# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC 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 is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_KOBJECT 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=y
 # CONFIG_DEBUG_ICEDCC is not set
@@ -796,6 +862,7 @@ CONFIG_DEBUG_S3C2410_UART=0
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
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
index b5e2602..e98f061 100644 (file)
@@ -65,7 +65,7 @@ CONFIG_KMOD=y
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_OMAP is not set
-CONFIG_ARCH_VERSATILE_PB=y
+CONFIG_ARCH_VERSATILE=y
 
 #
 # CLPS711X/EP721X Implementations
@@ -109,6 +109,12 @@ CONFIG_ARCH_VERSATILE_PB=y
 # S3C2410 Implementations
 #
 
+#
+# Versatile platform type
+#
+CONFIG_ARCH_VERSATILE_PB=y
+# CONFIG_MACH_VERSATILE_AB is not set
+
 #
 # Processor Type
 #
@@ -144,8 +150,8 @@ CONFIG_ZBOOT_ROM_BSS=0x0
 #
 # At least one math emulation must be selected
 #
-# CONFIG_FPE_NWFPE is not set
-CONFIG_FPE_FASTFPE=y
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
index 6f79381..894de5a 100644 (file)
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#define FIQ_VECTOR (vectors_base() + 0x1c)
-
 static unsigned long no_fiq_insn;
 
-static inline void unprotect_page_0(void)
-{
-       modify_domain(DOMAIN_USER, DOMAIN_MANAGER);
-}
-
-static inline void protect_page_0(void)
-{
-       modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
-}
-
 /* Default reacquire function
  * - we always relinquish FIQ control
  * - we always reacquire FIQ control
  */
 static int fiq_def_op(void *ref, int relinquish)
 {
-       if (!relinquish) {
-               unprotect_page_0();
-               *(unsigned long *)FIQ_VECTOR = no_fiq_insn;
-               protect_page_0();
-               flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + 4);
-       }
+       if (!relinquish)
+               set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
 
        return 0;
 }
@@ -93,12 +77,10 @@ int show_fiq_list(struct seq_file *p, void *v)
 
 void set_fiq_handler(void *start, unsigned int length)
 {
-       unprotect_page_0();
-
-       memcpy((void *)FIQ_VECTOR, start, length);
-
-       protect_page_0();
-       flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + length);
+       memcpy((void *)0xffff001c, start, length);
+       flush_icache_range(0xffff001c, 0xffff001c + length);
+       if (!vectors_high())
+               flush_icache_range(0x1c, 0x1c + length);
 }
 
 /*
@@ -198,6 +180,5 @@ EXPORT_SYMBOL(disable_fiq);
 
 void __init init_FIQ(void)
 {
-       no_fiq_insn = *(unsigned long *)FIQ_VECTOR;
-       set_fs(get_fs());
+       no_fiq_insn = *(unsigned long *)0xffff001c;
 }
index 9e8868b..6c20c11 100644 (file)
@@ -7,7 +7,7 @@
  * Copy data from IO memory space to "real" memory space.
  * This needs to be optimized.
  */
-void _memcpy_fromio(void *to, unsigned long from, size_t count)
+void _memcpy_fromio(void *to, void __iomem *from, size_t count)
 {
        unsigned char *t = to;
        while (count) {
@@ -22,7 +22,7 @@ void _memcpy_fromio(void *to, unsigned long from, size_t count)
  * Copy data from "real" memory space to IO memory space.
  * This needs to be optimized.
  */
-void _memcpy_toio(unsigned long to, const void *from, size_t count)
+void _memcpy_toio(void __iomem *to, const void *from, size_t count)
 {
        const unsigned char *f = from;
        while (count) {
@@ -37,7 +37,7 @@ void _memcpy_toio(unsigned long to, const void *from, size_t count)
  * "memset" on IO memory space.
  * This needs to be optimized.
  */
-void _memset_io(unsigned long dst, int c, size_t count)
+void _memset_io(void __iomem *dst, int c, size_t count)
 {
        while (count) {
                count--;
index a16951f..eb9240e 100644 (file)
@@ -9,6 +9,7 @@
  *
  * Module allocation method suggested by Andi Kleen.
  */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/elf.h>
 
 #include <asm/pgtable.h>
 
+#ifdef CONFIG_XIP_KERNEL
+/*
+ * The XIP kernel text is mapped in the module area for modules and
+ * some other stuff to work without any indirect relocations.
+ * MODULE_START is redefined here and not in asm/memory.h to avoid
+ * recompiling the whole kernel when CONFIG_XIP_KERNEL is turned on/off.
+ */
+extern void _etext;
+#undef MODULE_START
+#define MODULE_START   (((unsigned long)&_etext + ~PGDIR_MASK) & PGDIR_MASK)
+#endif
+
 void *module_alloc(unsigned long size)
 {
        struct vm_struct *area;
index 1131500..b885d32 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <asm-generic/vmlinux.lds.h>
+#include <linux/config.h>
        
 OUTPUT_ARCH(arm)
 ENTRY(stext)
@@ -17,7 +18,6 @@ SECTIONS
        . = TEXTADDR;
        .init : {                       /* Init code and data           */
                _stext = .;
-               __init_begin = .;
                        _sinittext = .;
                        *(.init.text)
                        _einittext = .;
@@ -30,7 +30,6 @@ SECTIONS
                __tagtable_begin = .;
                        *(.taglist)
                __tagtable_end = .;
-                       *(.init.data)
                . = ALIGN(16);
                __setup_start = .;
                        *(.init.setup)
@@ -57,8 +56,16 @@ SECTIONS
                __initramfs_start = .;
                        usr/built-in.o(.init.ramfs)
                __initramfs_end = .;
+               . = ALIGN(64);
+               __per_cpu_start = .;
+                       *(.data.percpu)
+               __per_cpu_end = .;
+#ifndef CONFIG_XIP_KERNEL
+               __init_begin = _stext;
+               *(.init.data)
                . = ALIGN(4096);
                __init_end = .;
+#endif
        }
 
        /DISCARD/ : {                   /* Exit code and data           */
@@ -79,8 +86,6 @@ SECTIONS
                        *(.glue_7)
                        *(.glue_7t)
                *(.got)                 /* Global offset table          */
-
-               _etext = .;             /* End of text section          */
        }
 
        . = ALIGN(16);
@@ -92,15 +97,33 @@ SECTIONS
 
        RODATA
 
+       _etext = .;                     /* End of text and rodata section */
+
+#ifdef CONFIG_XIP_KERNEL
+       __data_loc = ALIGN(4);          /* location in binary */
+       . = DATAADDR;
+#else
        . = ALIGN(8192);
+       __data_loc = .;
+#endif
+
+       .data : AT(__data_loc) {
+               __data_start = .;       /* address in memory */
 
-       .data : {
                /*
                 * first, the init task union, aligned
                 * to an 8192 byte boundary.
                 */
                *(.init.task)
 
+#ifdef CONFIG_XIP_KERNEL
+               . = ALIGN(4096);
+               __init_begin = .;
+               *(.init.data)
+               . = ALIGN(4096);
+               __init_end = .;
+#endif
+
                . = ALIGN(4096);
                __nosave_begin = .;
                *(.data.nosave)
@@ -126,7 +149,7 @@ SECTIONS
                __bss_start = .;        /* BSS                          */
                *(.bss)
                *(COMMON)
-               _end = . ;
+               _end = .;
        }
                                        /* Stabs debugging sections.    */
        .stab 0 : { *(.stab) }
index 007a5a0..c0e6583 100644 (file)
@@ -12,12 +12,12 @@ lib-y               := backtrace.o changebit.o csumipv6.o csumpartial.o   \
                   testclearbit.o testsetbit.o uaccess.o getuser.o    \
                   putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o   \
                   ucmpdi2.o udivdi3.o lib1funcs.o div64.o            \
-                  io-readsb.o io-writesb.o io-writesl.o
+                  io-readsb.o io-writesb.o io-readsl.o io-writesl.o
 
 ifeq ($(CONFIG_CPU_32v3),y)
-  lib-y        += io-readsw-armv3.o io-writesw-armv3.o io-readsl-armv3.o
+  lib-y        += io-readsw-armv3.o io-writesw-armv3.o
 else
-  lib-y        += io-readsw-armv4.o io-writesw-armv4.o io-readsl-armv4.o
+  lib-y        += io-readsw-armv4.o io-writesw-armv4.o
 endif
 
 lib-$(CONFIG_ARCH_RPC)         += ecard.o io-acorn.o floppydma.o
index c5515f3..cb5e370 100644 (file)
@@ -73,8 +73,7 @@ td3   .req    lr
 .done:         adc     r0, sum, #0             @ collect up the last carry
                ldr     td0, [sp], #4
                tst     td0, #1                 @ check buffer alignment
-               movne   td0, r0, lsl #8         @ rotate checksum by 8 bits
-               orrne   r0, td0, r0, lsr #24
+               movne   r0, r0, ror #8          @ rotate checksum by 8 bits
                ldr     pc, [sp], #4            @ return
 
 .not_aligned:  tst     buf, #1                 @ odd address
index b18b897..d3a2f46 100644 (file)
@@ -160,8 +160,7 @@ FN_ENTRY
 .done:         adc     r0, sum, #0
                ldr     sum, [sp, #0]           @ dst
                tst     sum, #1
-               movne   sum, r0, lsl #8
-               orrne   r0, sum, r0, lsr #24
+               movne   r0, r0, ror #8
                load_regs       ea
 
 .src_not_aligned:
index 67cbd86..3c7f7e6 100644 (file)
@@ -16,15 +16,16 @@ LC0:                .word   loops_per_jiffy
 /*
  * 0 <= r0 <= 2000
  */
-ENTRY(udelay)
+ENTRY(__udelay)
                mov     r2,     #0x6800
                orr     r2, r2, #0x00db
-               mul     r1, r0, r2
+               mul     r0, r2, r0
+ENTRY(__const_udelay)                          @ 0 <= r0 <= 0x01ffffff
                ldr     r2, LC0
-               ldr     r2, [r2]
-               mov     r1, r1, lsr #11
-               mov     r2, r2, lsr #11
-               mul     r0, r1, r2
+               ldr     r2, [r2]                @ max = 0x0fffffff
+               mov     r0, r0, lsr #11         @ max = 0x00003fff
+               mov     r2, r2, lsr #11         @ max = 0x0003ffff
+               mul     r0, r2, r0              @ max = 2^32-1
                movs    r0, r0, lsr #6
                RETINSTR(moveq,pc,lr)
 
index 9478e01..64aa6f4 100644 (file)
@@ -17,7 +17,7 @@
  *
  * Inputs:     r0 contains the address
  * Outputs:    r0 is the error code
- *             r1, r2 contains the zero-extended value
+ *             r2, r3 contains the zero-extended value
  *             lr corrupted
  *
  * No other registers must be altered.  (see include/asm-arm/uaccess.h
 
        .global __get_user_1
 __get_user_1:
-1:     ldrbt   r1, [r0]
+1:     ldrbt   r2, [r0]
        mov     r0, #0
        mov     pc, lr
 
        .global __get_user_2
 __get_user_2:
-2:     ldrbt   r1, [r0], #1
-3:     ldrbt   r2, [r0]
+2:     ldrbt   r2, [r0], #1
+3:     ldrbt   r3, [r0]
 #ifndef __ARMEB__
-       orr     r1, r1, r2, lsl #8
+       orr     r2, r2, r3, lsl #8
 #else
-       orr     r1, r2, r1, lsl #8
+       orr     r2, r3, r2, lsl #8
 #endif
        mov     r0, #0
        mov     pc, lr
 
        .global __get_user_4
 __get_user_4:
-4:     ldrt    r1, [r0]
+4:     ldrt    r2, [r0]
        mov     r0, #0
        mov     pc, lr
 
        .global __get_user_8
 __get_user_8:
-5:     ldrt    r1, [r0], #4
-6:     ldrt    r2, [r0]
+5:     ldrt    r2, [r0], #4
+6:     ldrt    r3, [r0]
        mov     r0, #0
        mov     pc, lr
 
 __get_user_bad_8:
-       mov     r2, #0
+       mov     r3, #0
 __get_user_bad:
-       mov     r1, #0
+       mov     r2, #0
        mov     r0, #-EFAULT
        mov     pc, lr
 
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
index 20b3ee2..f8f14dd 100644 (file)
@@ -9,53 +9,58 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/hardware.h>
 
 ENTRY(__raw_writesl)
                teq     r2, #0          @ do we have to check for the zero len?
                moveq   pc, lr
                ands    ip, r1, #3
-               bne     2f
+               bne     3f
 
-               tst     r2, #1
-               ldrne   r3, [r1], #4
-               strne   r3, [r0, #0]
-1:             subs    r2, r2, #2
-               ldrcs   r3, [r1], #4
-               ldrcs   ip, [r1], #4
+               subs    r2, r2, #4
+               bmi     2f
+               stmfd   sp!, {r4, lr}
+1:             ldmia   r1!, {r3, r4, ip, lr}
+               subs    r2, r2, #4
+               str     r3, [r0, #0]
+               str     r4, [r0, #0]
+               str     ip, [r0, #0]
+               str     lr, [r0, #0]
+               bpl     1b
+               ldmfd   sp!, {r4, lr}
+2:             movs    r2, r2, lsl #31
+               ldmcsia r1!, {r3, ip}
                strcs   r3, [r0, #0]
+               ldrne   r3, [r1, #0]
                strcs   ip, [r0, #0]
-               bcs     1b
+               strne   r3, [r0, #0]
                mov     pc, lr
 
-2:             bic     r1, r1, #3
-               cmp     ip, #2
+3:             bic     r1, r1, #3
                ldr     r3, [r1], #4
-               bgt     4f
+               cmp     ip, #2
                blt     5f
+               bgt     6f
 
-3:             mov     ip, r3, lsr #16
+4:             mov     ip, r3, pull #16
                ldr     r3, [r1], #4
                subs    r2, r2, #1
-               orr     ip, ip, r3, lsl #16
-               str     ip, [r0, #0]
-               bne     3b
+               orr     ip, ip, r3, push #16
+               str     ip, [r0]
+               bne     4b
                mov     pc, lr
 
-4:             mov     ip, r3, lsr #24
+5:             mov     ip, r3, pull #8
                ldr     r3, [r1], #4
                subs    r2, r2, #1
-               orr     ip, ip, r3, lsl #8
-               str     ip, [r0, #0]
-               bne     4b
+               orr     ip, ip, r3, push #24
+               str     ip, [r0]
+               bne     5b
                mov     pc, lr
 
-5:             mov     ip, r3, lsr #8
+6:             mov     ip, r3, pull #24
                ldr     r3, [r1], #4
                subs    r2, r2, #1
-               orr     ip, ip, r3, lsl #24
-               str     ip, [r0, #0]
-               bne     5b
+               orr     ip, ip, r3, push #8
+               str     ip, [r0]
+               bne     6b
                mov     pc, lr
-
-
index 05ec1ab..179eea4 100644 (file)
 #define UDIV_NEEDS_NORMALIZATION 1
 #define udiv_qrnnd __udiv_qrnnd_c
 
-extern const UQItype __clz_tab[];
 #define count_leading_zeros(count, x) \
   do {                                                                 \
     USItype __xr = (x);                                                        \
index b978885..b09398d 100644 (file)
@@ -16,7 +16,7 @@
  * __put_user_X
  *
  * Inputs:     r0 contains the address
- *             r1, r2 contains the value
+ *             r2, r3 contains the value
  * Outputs:    r0 is the error code
  *             lr corrupted
  *
 
        .global __put_user_1
 __put_user_1:
-1:     strbt   r1, [r0]
+1:     strbt   r2, [r0]
        mov     r0, #0
        mov     pc, lr
 
        .global __put_user_2
 __put_user_2:
-       mov     ip, r1, lsr #8
+       mov     ip, r2, lsr #8
 #ifndef __ARMEB__
-2:     strbt   r1, [r0], #1
+2:     strbt   r2, [r0], #1
 3:     strbt   ip, [r0]
 #else
 2:     strbt   ip, [r0], #1
-3:     strbt   r1, [r0]
+3:     strbt   r2, [r0]
 #endif
        mov     r0, #0
        mov     pc, lr
 
        .global __put_user_4
 __put_user_4:
-4:     strt    r1, [r0]
+4:     strt    r2, [r0]
        mov     r0, #0
        mov     pc, lr
 
        .global __put_user_8
 __put_user_8:
-5:     strt    r1, [r0], #4
-6:     strt    r2, [r0]
+5:     strt    r2, [r0], #4
+6:     strt    r3, [r0]
        mov     r0, #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
+
index 1eaea0b..fc3250d 100644 (file)
@@ -4,6 +4,7 @@ menu "Footbridge Implementations"
 
 config ARCH_CATS
        bool "CATS"
+       select FOOTBRIDGE_HOST
        help
          Say Y here if you intend to run this kernel on the CATS.
 
@@ -11,6 +12,7 @@ config ARCH_CATS
 
 config ARCH_PERSONAL_SERVER
        bool "Compaq Personal Server"
+       select FOOTBRIDGE_HOST
        ---help---
          Say Y here if you intend to run this kernel on the Compaq
          Personal Server.
@@ -28,6 +30,8 @@ config ARCH_PERSONAL_SERVER
 
 config ARCH_EBSA285_ADDIN
        bool "EBSA285 (addin mode)"
+       select ARCH_EBSA285
+       select FOOTBRIDGE_ADDIN
        help
          Say Y here if you intend to run this kernel on the EBSA285 card
          in addin mode.
@@ -36,6 +40,8 @@ config ARCH_EBSA285_ADDIN
 
 config ARCH_EBSA285_HOST
        bool "EBSA285 (host mode)"
+       select ARCH_EBSA285
+       select FOOTBRIDGE_HOST
        help
          Say Y here if you intend to run this kernel on the EBSA285 card
          in host ("central function") mode.
@@ -44,6 +50,7 @@ config ARCH_EBSA285_HOST
 
 config ARCH_NETWINDER
        bool "NetWinder"
+       select FOOTBRIDGE_HOST
        help
          Say Y here if you intend to run this kernel on the Rebel.COM
          NetWinder.  Information about this machine can be found at:
@@ -54,4 +61,20 @@ config ARCH_NETWINDER
 
 endmenu
 
+# Footbridge support
+config FOOTBRIDGE
+       bool
+
+# Footbridge in host mode
+config FOOTBRIDGE_HOST
+       bool
+
+# Footbridge in addin mode
+config FOOTBRIDGE_ADDIN
+       bool
+
+# EBSA285 board in either host or addin mode
+config ARCH_EBSA285
+       bool
+
 endif
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
+
index 0aec69f..f94d176 100644 (file)
@@ -9,8 +9,14 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 
+#include <asm/hardware/dec21285.h>
 #include <asm/io.h>
 #include <asm/mach-types.h>
+#include <asm/setup.h>
+
+#include <asm/mach/arch.h>
+
+#include "common.h"
 
 #define CFG_PORT       0x370
 #define INDEX_PORT     (CFG_PORT)
@@ -62,3 +68,27 @@ static int __init cats_hw_init(void)
 }
 
 __initcall(cats_hw_init);
+
+/*
+ * CATS uses soft-reboot by default, since
+ * hard reboots fail on early boards.
+ */
+static void __init
+fixup_cats(struct machine_desc *desc, struct tag *tags,
+          char **cmdline, struct meminfo *mi)
+{
+       ORIG_VIDEO_LINES  = 25;
+       ORIG_VIDEO_POINTS = 16;
+       ORIG_Y = 24;
+}
+
+MACHINE_START(CATS, "Chalice-CATS")
+       MAINTAINER("Philip Blundell")
+       BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+       BOOT_PARAMS(0x00000100)
+       SOFT_REBOOT
+       FIXUP(fixup_cats)
+       MAPIO(footbridge_map_io)
+       INITIRQ(footbridge_init_irq)
+       .timer          = &isa_timer,
+MACHINE_END
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);
index c81775b..5ec9ea9 100644 (file)
 #include <linux/delay.h>
 #include <linux/init.h>
 
+#include <asm/hardware/dec21285.h>
 #include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
+#include <asm/setup.h>
+
+#include <asm/mach/arch.h>
+
+#include "common.h"
 
 #define IRDA_IO_BASE           0x180
 #define GP1_IO_BASE            0x338
@@ -52,7 +58,7 @@ static inline void wb977_ww(int reg, int val)
        outb(reg, 0x370);
        outb(val >> 8, 0x371);
        outb(reg + 1, 0x370);
-       outb(val, 0x371);
+       outb(val & 255, 0x371);
 }
 
 #define wb977_device_select(dev)       wb977_wb(0x07, dev)
@@ -482,7 +488,7 @@ static inline void rwa010_waveartist_init(int base, int irq, int dma)
        WRITE_RWA(7, 0);
 
        dprintk("WaveArtist base: ");
-       WRITE_RWA(0x61, base);
+       WRITE_RWA(0x61, base & 255);
        i = inb(0x203);
 
        WRITE_RWA(0x60, base >> 8);
@@ -504,7 +510,7 @@ static inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, i
        WRITE_RWA(7, 1);
 
        dprintk("SoundBlaster base: ");
-       WRITE_RWA(0x61, sb_base);
+       WRITE_RWA(0x61, sb_base & 255);
        i = inb(0x203);
 
        WRITE_RWA(0x60, sb_base >> 8);
@@ -519,7 +525,7 @@ static inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, i
        dprintk("%d (%d)\n", inb(0x203), dma);
 
        dprintk("AdLib base: ");
-       WRITE_RWA(0x63, al_base);
+       WRITE_RWA(0x63, al_base & 255);
        i = inb(0x203);
 
        WRITE_RWA(0x62, al_base >> 8);
@@ -618,3 +624,37 @@ static int __init nw_hw_init(void)
 }
 
 __initcall(nw_hw_init);
+
+/*
+ * Older NeTTroms either do not provide a parameters
+ * page, or they don't supply correct information in
+ * the parameter page.
+ */
+static void __init
+fixup_netwinder(struct machine_desc *desc, struct tag *tags,
+               char **cmdline, struct meminfo *mi)
+{
+#ifdef CONFIG_ISAPNP
+       extern int isapnp_disable;
+
+       /*
+        * We must not use the kernels ISAPnP code
+        * on the NetWinder - it will reset the settings
+        * for the WaveArtist chip and render it inoperable.
+        */
+       isapnp_disable = 1;
+#endif
+}
+
+MACHINE_START(NETWINDER, "Rebel-NetWinder")
+       MAINTAINER("Russell King/Rebel.com")
+       BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+       BOOT_PARAMS(0x00000100)
+       VIDEO(0x000a0000, 0x000bffff)
+       DISABLE_PARPORT(0)
+       DISABLE_PARPORT(2)
+       FIXUP(fixup_netwinder)
+       MAPIO(footbridge_map_io)
+       INITIRQ(footbridge_init_irq)
+       .timer          = &isa_timer,
+MACHINE_END
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
+
index e9f5708..2c64a0b 100644 (file)
 
 #include <linux/timex.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/mc146818rtc.h>
 #include <linux/bcd.h>
 
-#include <asm/hardware/dec21285.h>
-
 #include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
 #include <asm/io.h>
-#include <asm/hardware/clps7111.h>
 
 #include <asm/mach/time.h>
+#include "common.h"
 
 static int rtc_base;
 
-#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)
-{
-       timer_tick(regs);
-
-       return IRQ_HANDLED;
-}
-
 static unsigned long __init get_isa_cmos_time(void)
 {
        unsigned int year, mon, day, hour, min, sec;
@@ -133,8 +76,7 @@ static unsigned long __init get_isa_cmos_time(void)
        return mktime(year, mon, day, hour, min, sec);
 }
 
-static int
-set_isa_cmos_time(void)
+static int set_isa_cmos_time(void)
 {
        int retval = 0;
        int real_seconds, real_minutes, cmos_minutes;
@@ -186,34 +128,7 @@ set_isa_cmos_time(void)
        return retval;
 }
 
-
-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)
-{
-       *CSR_TIMER1_CLR = 0;
-
-       timer_tick(regs);
-
-       return IRQ_HANDLED;
-}
-
-static struct irqaction footbridge_timer_irq = {
-       .flags  = SA_INTERRUPT
-};
-
-/*
- * Set up timer interrupt.
- */
-void __init footbridge_init_time(void)
+void __init isa_rtc_init(void)
 {
        if (machine_is_co285() ||
            machine_is_personal_server())
@@ -262,35 +177,4 @@ void __init footbridge_init_time(void)
                } else
                        rtc_base = 0;
        }
-
-       if (machine_is_ebsa285() ||
-           machine_is_co285() ||
-           machine_is_personal_server()) {
-               gettimeoffset = timer1_gettimeoffset;
-
-               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;
-
-               footbridge_timer_irq.name = "Timer1 Timer Tick";
-               footbridge_timer_irq.handler = timer1_interrupt;
-               
-               setup_irq(IRQ_TIMER1, &footbridge_timer_irq);
-
-       } else {
-               /* 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);
-
-               gettimeoffset = isa_gettimeoffset;
-
-               footbridge_timer_irq.name = "ISA Timer Tick";
-               footbridge_timer_irq.handler = isa_timer_interrupt;
-               
-               setup_irq(IRQ_ISA_TIMER, &footbridge_timer_irq);
-       }
 }
index 44a303d..5890fa8 100644 (file)
@@ -1,3 +1,5 @@
+if ARCH_H720X
+
 menu "h720x Implementations"
 
 config ARCH_H7201
@@ -25,3 +27,5 @@ config CPU_H7202
        bool
        help
          Select code specific to h7202 variants
+
+endif
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.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
index 30f4d61..7436568 100644 (file)
 #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);
-
+#include "common.h"
 /*
  * Timer interrupt handler
  */
 static irqreturn_t
 h7201_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+       write_seqlock(&xtime_lock);
+
        CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
        timer_tick(regs);
+
+       write_sequnlock(&xtime_lock);
+
        return IRQ_HANDLED;
 }
 
@@ -48,8 +50,6 @@ static struct irqaction h7201_timer_irq = {
  */
 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;
@@ -57,3 +57,8 @@ void __init h7201_init_time(void)
 
        setup_irq(IRQ_TIMER0, &h7201_timer_irq);
 }
+
+struct sys_timer h7201_timer = {
+       .init           = h7201_init_time,
+       .offset         = h720x_gettimeoffset,
+};
index ee7abcd..4b6968e 100644 (file)
@@ -23,6 +23,8 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 #include <linux/device.h>
+#include <linux/serial_8250.h>
+#include "common.h"
 
 static struct resource h7202ps2_resources[] = {
        [0] = {
@@ -44,13 +46,55 @@ static struct platform_device h7202ps2_device = {
        .resource       = h7202ps2_resources,
 };
 
+static struct plat_serial8250_port serial_platform_data[] = {
+       {
+               .membase        = SERIAL0_BASE,
+               .irq            = IRQ_UART0,
+               .uartclk        = 2*1843200,
+               .regshift       = 2,
+               .iotype         = UPIO_MEM,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+       },
+       {
+               .membase        = SERIAL1_BASE,
+               .irq            = IRQ_UART1,
+               .uartclk        = 2*1843200,
+               .regshift       = 2,
+               .iotype         = UPIO_MEM,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+       },
+       {
+               .membase        = SERIAL2_BASE,
+               .irq            = IRQ_UART2,
+               .uartclk        = 2*1843200,
+               .regshift       = 2,
+               .iotype         = UPIO_MEM,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+       },
+       {
+               .membase        = SERIAL3_BASE,
+               .irq            = IRQ_UART3,
+               .uartclk        = 2*1843200,
+               .regshift       = 2,
+               .iotype         = UPIO_MEM,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+       },
+       { },
+};
+
+static struct platform_device serial_device = {
+       .name                   = "serial8250",
+       .id                     = 0,
+       .dev                    = {
+               .platform_data  = serial_platform_data,
+       },
+};
+
 static struct platform_device *devices[] __initdata = {
        &h7202ps2_device,
+       &serial_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.
@@ -64,7 +108,9 @@ h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
        mask = CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
 
        if ( mask & TSTAT_T0INT ) {
+               write_seqlock(&xtime_lock);
                timer_tick(regs);
+               write_sequnlock(&xtime_lock);
                if( mask == TSTAT_T0INT )
                        return;
        }
@@ -128,8 +174,6 @@ static struct irqaction h7202_timer_irq = {
  */
 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;
@@ -138,6 +182,11 @@ void __init h7202_init_time(void)
        setup_irq(IRQ_TIMER0, &h7202_timer_irq);
 }
 
+struct sys_timer h7202_timer = {
+       .init           = h7202_init_time,
+       .offset         = h720x_gettimeoffset,
+};
+
 void __init h7202_init_irq (void)
 {
        int     irq;
index d2208c1..9b24b9b 100644 (file)
 #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);
+#include "common.h"
 
 MACHINE_START(H7201, "Hynix GMS30C7201")
        MAINTAINER("Robert Schwebel, Pengutronix")
@@ -38,5 +35,5 @@ MACHINE_START(H7201, "Hynix GMS30C7201")
        BOOT_PARAMS(0xc0001000)
        MAPIO(h720x_map_io)
        INITIRQ(h720x_init_irq)
-       INITTIME(h7201_init_time)
+       .timer = &h7201_timer,
 MACHINE_END
index 9398731..3456a00 100644 (file)
 #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);
+#include "common.h"
 
 static struct resource cirrus_resources[] = {
        [0] = {
@@ -80,6 +76,6 @@ MACHINE_START(H7202, "Hynix HMS30C7202")
        BOOT_PARAMS(0x40000100)
        MAPIO(h720x_map_io)
        INITIRQ(h7202_init_irq)
-       INITTIME(h7202_init_time)
+       .timer = &h7202_timer,
        INIT_MACHINE(init_eval_h7202)
 MACHINE_END
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
+
index 31e1911..e91003e 100644 (file)
@@ -11,4 +11,6 @@
 
 extern void __init imx_map_io(void);
 extern void __init imx_init_irq(void);
-extern void __init imx_init_time(void);
+
+struct sys_timer;
+extern struct sys_timer imx_timer;
index bd92b90..625dd01 100644 (file)
@@ -83,6 +83,6 @@ MACHINE_START(MX1ADS, "Motorola MX1ADS")
        BOOT_PARAMS(0x08000100)
        MAPIO(mx1ads_map_io)
        INITIRQ(imx_init_irq)
-       INITTIME(imx_init_time)
+       .timer          = &imx_timer,
        INIT_MACHINE(mx1ads_init)
 MACHINE_END
index ac7cab9..11f1e56 100644 (file)
@@ -28,8 +28,7 @@
  * Returns number of us since last clock interrupt.  Note that interrupts
  * will have been disabled by do_gettimeoffset()
  */
-static unsigned long
-imx_gettimeoffset(void)
+static unsigned long imx_gettimeoffset(void)
 {
        unsigned long ticks;
 
@@ -59,11 +58,15 @@ imx_gettimeoffset(void)
 static irqreturn_t
 imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+       write_seqlock(&xtime_lock);
+
        /* clear the interrupt */
        if (IMX_TSTAT(TIMER_BASE))
                IMX_TSTAT(TIMER_BASE) = 0;
 
        timer_tick(regs);
+       write_sequnlock(&xtime_lock);
+
        return IRQ_HANDLED;
 }
 
@@ -76,8 +79,7 @@ static struct irqaction imx_timer_irq = {
 /*
  * Set up timer interrupt, and return the current time in seconds.
  */
-void __init
-imx_init_time(void)
+static void __init imx_timer_init(void)
 {
        /*
         * Initialise to a known state (all timers off, and timing reset)
@@ -91,5 +93,9 @@ imx_init_time(void)
         * Make irqs happen for the system timer
         */
        setup_irq(TIM1_INT, &imx_timer_irq);
-       gettimeoffset = imx_gettimeoffset;
 }
+
+struct sys_timer imx_timer = {
+       .init           = imx_timer_init,
+       .offset         = 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);
index dcbffb6..e633dd9 100644 (file)
@@ -10,7 +10,7 @@ obj-m                 :=
 obj-n                  :=
 obj-                   :=
 
-obj-$(CONFIG_ARCH_IOP321)  += iop321-setup.o iop321-irq.o iop321-pci.o iop321-mm.o iop321-time.o
+obj-$(CONFIG_ARCH_IOP321)  += iop321-setup.o iop321-irq.o iop321-pci.o iop321-time.o
 
 obj-$(CONFIG_ARCH_IOP331)  += iop331-setup.o iop331-irq.o iop331-pci.o iop331-time.o
 
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
+
index c0bbe5a..bda7394 100644 (file)
@@ -28,7 +28,6 @@ unsigned long iop3xx_pcibios_min_mem = 0;
  * Default power-off for EP80219
  */
 #include <asm/mach-types.h>
-#include <asm/hardware.h>
 
 static inline void ep80219_send_to_pic(__u8 c) {
 }
index e92f77f..12e4a78 100644 (file)
@@ -9,11 +9,21 @@
  * 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/mach-types.h>
 #include <asm/mach/arch.h>
 
+#define IOP321_UART_XTAL 1843200
+
+/*
+ * Standard IO mapping for all IOP321 based systems
+ */
+static struct map_desc iop321_std_desc[] __initdata = {
+ /* virtual     physical      length      type */
+
+ /* mem mapped registers */
+ { IOP321_VIRT_MEM_BASE,  IOP321_PHY_MEM_BASE,   0x00002000,  MT_DEVICE },
+
+ /* PCI IO space */
+ { 0xfe000000,  0x90000000,   0x00020000,  MT_DEVICE }
+};
+
+#ifdef CONFIG_ARCH_IQ80321
+#define UARTBASE IQ80321_UART
+#define IRQ_UART IRQ_IQ80321_UART
+#endif
+
+#ifdef CONFIG_ARCH_IQ31244
+#define UARTBASE IQ31244_UART
+#define IRQ_UART IRQ_IQ31244_UART
+#endif
+
+static struct uart_port iop321_serial_ports[] = {
+       {
+               .membase        = (char*)(UARTBASE),
+               .mapbase        = (UARTBASE),
+               .irq            = IRQ_UART,
+               .flags          = UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = IOP321_UART_XTAL,
+               .line           = 0,
+               .type           = PORT_16550A,
+               .fifosize       = 16
+       }
+};
+
+void __init iop321_map_io(void)
+{
+       iotable_init(iop321_std_desc, ARRAY_SIZE(iop321_std_desc));
+       early_serial_setup(&iop321_serial_ports[0]);
+}
+
 #ifdef CONFIG_ARCH_IQ80321
 extern void iq80321_map_io(void);
-extern void iop321_init_irq(void);
+extern struct sys_timer iop321_timer;
 extern void iop321_init_time(void);
 #endif
 
 #ifdef CONFIG_ARCH_IQ31244
 extern void iq31244_map_io(void);
-extern void iop321_init_irq(void);
+extern struct sys_timer iop321_timer;
 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)
+       BOOT_MEM(PHYS_OFFSET, IQ80321_UART, IQ80321_UART)
        MAPIO(iq80321_map_io)
        INITIRQ(iop321_init_irq)
-       INITTIME(iop321_init_time)
+       .timer          = &iop321_timer,
     BOOT_PARAMS(0xa0000100)
 MACHINE_END
 #elif defined(CONFIG_ARCH_IQ31244)
-    MACHINE_START(IQ31244, "Intel 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)
+       .timer          = &iop321_timer,
     BOOT_PARAMS(0xa0000100)
 MACHINE_END
 #else
index 681e1ce..6cb68f3 100644 (file)
@@ -12,7 +12,6 @@
 #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>
@@ -81,7 +80,7 @@ void __init iop331_map_io(void)
 
 #ifdef CONFIG_ARCH_IQ80331
 extern void iop331_init_irq(void);
-extern void iop331_init_time(void);
+extern struct sys_timer iop331_timer;
 extern void iq80331_map_io(void);
 #endif
 
@@ -92,7 +91,7 @@ MACHINE_START(IQ80331, "Intel IQ80331")
     //BOOT_MEM(PHYS_OFFSET, IQ80331_UART0_VIRT, IQ80331_UART0_PHYS)
     MAPIO(iq80331_map_io)
     INITIRQ(iop331_init_irq)
-    INITTIME(iop331_init_time)
+    .timer             = &iop331_timer,
     BOOT_PARAMS(0x0100)
 MACHINE_END
 #else
index c90a0c9..e016967 100644 (file)
 #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;
+       return LATCH - *IOP331_TU_TCR0;
 }
 
 static unsigned long iop331_gettimeoffset(void)
@@ -55,14 +51,14 @@ static unsigned long iop331_gettimeoffset(void)
        asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
 
        if(tisr1 & 1)
-               elapsed += iop331_latch;
+               elapsed += LATCH;
        else if (tisr2 & 1)
-               elapsed = iop331_latch + get_elapsed();
+               elapsed = LATCH + get_elapsed();
 
        /*
         * Now convert them to usec.
         */
-       usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / iop331_latch;
+       usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
 
        return usec;
 }
@@ -71,36 +67,16 @@ 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));
+       write_seqlock(&xtime_lock);
 
+       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
+       timer_tick(regs);
 
+       write_sequnlock(&xtime_lock);
        return IRQ_HANDLED;
 }
 
@@ -110,32 +86,22 @@ static struct irqaction iop331_timer_irq = {
        .flags          = SA_INTERRUPT
 };
 
-extern int setup_arm_irq(int, struct irqaction*);
-
-void __init iop331_init_time(void)
+static void __init iop331_timer_init(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, c4, c1, 0" : : "r" (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
 }
 
-
+struct sys_timer iop331_timer = {
+       .init           = iop331_timer_init,
+       .offset         = iop331_gettimeoffset,
+};
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
+
index 2d66337..0b59703 100644 (file)
@@ -9,7 +9,7 @@
  *
  * Based on work Copyright (C) 2002-2003 Intel Corporation
  * 
- * This file is licensed under  the terms of the GNU General Public 
+ * 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 <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>
@@ -170,7 +168,7 @@ void __init ixp2000_map_io(void)
 static unsigned ticks_per_jiffy;
 static unsigned ticks_per_usec;
 
-static unsigned long ixp2000_gettimeoffset (void)
+unsigned long ixp2000_gettimeoffset (void)
 {
        unsigned long elapsed;
 
@@ -182,11 +180,15 @@ static unsigned long ixp2000_gettimeoffset (void)
 
 static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+       write_seqlock(&xtime_lock);
+
        /* clear timer 1 */
        ixp2000_reg_write(IXP2000_T1_CLR, 1);
        
        timer_tick(regs);
 
+       write_sequnlock(&xtime_lock);
+
        return IRQ_HANDLED;
 }
 
@@ -198,8 +200,6 @@ static struct irqaction ixp2000_timer_irq = {
 
 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);
 
@@ -309,41 +309,6 @@ static struct irqchip ixp2000_pci_irq_chip = {
        .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));
@@ -387,7 +352,7 @@ void __init ixp2000_init_irq(void)
         * 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++) {
+       for (irq = IRQ_IXP2000_SOFT_INT; 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);
@@ -409,18 +374,11 @@ void __init ixp2000_init_irq(void)
        /*
         * Enable PCI irq
         */
-       *(IXP2000_IRQ_ENABLE_SET) = (1 << IRQ_IXP2000_PCI);
+       ixp2000_reg_write(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);
 }
 
index a6e30d0..af894f4 100644 (file)
@@ -26,9 +26,6 @@
 #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>
 /*************************************************************************
  * ENP-2611 timer tick configuration
  *************************************************************************/
-static void __init enp2611_init_time(void)
+static void __init enp2611_timer_init(void)
 {
        ixp2000_init_time(50 * 1000 * 1000);
 }
 
+static struct enp2611_timer = {
+       .init           = enp2611_timer_init,
+       .offset         = ixp2000_gettimeoffset,
+};
+
 
 /*************************************************************************
  * ENP-2611 PCI
@@ -202,7 +204,7 @@ MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
        BOOT_PARAMS(0x00000100)
        MAPIO(ixp2000_map_io)
        INITIRQ(ixp2000_init_irq)
-       INITTIME(enp2611_init_time)
+       .timer          = &enp2611_timer,
        INIT_MACHINE(enp2611_init_machine)
 MACHINE_END
 #endif
index 39ef558..cd98116 100644 (file)
@@ -23,9 +23,6 @@
 #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>
@@ -48,7 +45,7 @@
 /*************************************************************************
  * IXDP2400 timer tick
  *************************************************************************/
-static void __init ixdp2400_init_time(void)
+static void __init ixdp2400_timer_init(void)
 {
        int numerator, denominator;
        int denom_array[] = {2, 4, 8, 16, 1, 2, 4, 8};
@@ -59,6 +56,11 @@ static void __init ixdp2400_init_time(void)
        ixp2000_init_time(((3125000 * numerator) / (denominator)) / 2);
 }
 
+static struct timer ixdp2400_timer = {
+       .init           = ixdp2400_timer_init,
+       .offset         = ixp2000_gettimeoffset,
+};
+
 /*************************************************************************
  * IXDP2400 PCI
  *************************************************************************/
@@ -171,7 +173,7 @@ MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
        BOOT_PARAMS(0x00000100)
        MAPIO(ixdp2x00_map_io)
        INITIRQ(ixdp2400_init_irq)
-       INITTIME(ixdp2400_init_time)
+       .timer          = &ixdp2400_timer,
        INIT_MACHINE(ixdp2x00_init_machine)
 MACHINE_END
 
index 285eaf0..49334b4 100644 (file)
@@ -23,9 +23,6 @@
 #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>
@@ -55,11 +52,16 @@ void ixdp2400_init_irq(void)
  * IXDP2800 timer tick
  *************************************************************************/
 
-static void __init ixdp2800_init_time(void)
+static void __init ixdp2800_timer_init(void)
 {
        ixp2000_init_time(50000000);
 }
 
+static struct sys_timer ixdp2800_timer = {
+       .init           = ixdp2800_timer_init,
+       .offset         = ixp2000_gettimeoffset,
+};
+
 /*************************************************************************
  * IXDP2800 PCI
  *************************************************************************/
@@ -172,7 +174,7 @@ MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
        BOOT_PARAMS(0x00000100)
        MAPIO(ixdp2x00_map_io)
        INITIRQ(ixdp2800_init_irq)
-       INITTIME(ixdp2800_init_time)
+       .timer          = &ixdp2800_timer,
        INIT_MACHINE(ixdp2x00_init_machine)
 MACHINE_END
 
index cda60b7..5df9992 100644 (file)
@@ -23,9 +23,6 @@
 #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>
@@ -197,7 +194,7 @@ void __init ixdp2x00_map_io(void)
  * 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:
+ * multiple hosts on the bus. The exact bus layout looks like:
  *
  *                   Bus 0
  *    Master NPU <-------------------+-------------------> Slave NPU
@@ -213,9 +210,9 @@ void __init ixdp2x00_map_io(void)
  *             ... 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
+ * slave. What this means 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
+ * In addition, after the bus is scanned, 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
index 176114a..0e919bb 100644 (file)
@@ -23,9 +23,6 @@
 #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>
  *************************************************************************/
 static void ixdp2x01_irq_mask(unsigned int irq)
 {
-       *IXDP2X01_INT_MASK_SET_REG = IXP2000_BOARD_IRQ_MASK(irq);
+       ixp2000_reg_write(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);
+       ixp2000_reg_write(IXDP2X01_INT_MASK_CLR_REG,
+                               IXP2000_BOARD_IRQ_MASK(irq));
 }
 
 static u32 valid_irq_mask;
@@ -114,8 +113,8 @@ void __init ixdp2x01_init_irq(void)
                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;
+       ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff);
+       ixp2000_reg_write(IXDP2X01_INT_SIM_REG, 0);
 
        for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) {
                if (irq & valid_irq_mask) {
@@ -193,7 +192,7 @@ static int __init ixdp2x01_clock_setup(char *str)
 
 __setup("ixdp2x01_clock=", ixdp2x01_clock_setup);
 
-static void __init ixdp2x01_init_time(void)
+static void __init ixdp2x01_timer_init(void)
 {
        if (!ixdp2x01_clock)
                ixdp2x01_clock = 50000000;
@@ -201,6 +200,11 @@ static void __init ixdp2x01_init_time(void)
        ixp2000_init_time(ixdp2x01_clock);
 }
 
+static struct sys_timer ixdp2x01_timer = {
+       .init           = ixdp2x01_timer_init,
+       .offset         = ixp2000_gettimeoffset,
+};
+
 /*************************************************************************
  * IXDP2x01 PCI
  *************************************************************************/
@@ -312,8 +316,8 @@ static struct flash_platform_data ixdp2x01_flash_platform_data = {
 
 static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs)
 {
-       *IXDP2X01_CPLD_FLASH_REG = 
-               ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN);
+       ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG,
+               ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN));
        return (ofs & IXDP2X01_FLASH_WINDOW_MASK);
 }
 
@@ -338,14 +342,29 @@ static struct platform_device ixdp2x01_flash = {
        .resource       = &ixdp2x01_flash_resource,
 };
 
+static struct ixp2000_i2c_pins ixdp2x01_i2c_gpio_pins = {
+       .sda_pin        = IXDP2X01_GPIO_SDA,
+       .scl_pin        = IXDP2X01_GPIO_SCL,
+};
+
+static struct platform_device ixdp2x01_i2c_controller = {
+       .name           = "IXP2000-I2C",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &ixdp2x01_i2c_gpio_pins,
+       },
+       .num_resources  = 0
+};
+
 static struct platform_device *ixdp2x01_devices[] __initdata = {
-       &ixdp2x01_flash
+       &ixdp2x01_flash,
+       &ixdp2x01_i2c_controller
 };
 
 static void __init ixdp2x01_init_machine(void)
 {
-       *IXDP2X01_CPLD_FLASH_REG = 
-               (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN);
+       ixp2000_reg_write(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);
@@ -361,7 +380,7 @@ MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
        BOOT_PARAMS(0x00000100)
        MAPIO(ixdp2x01_map_io)
        INITIRQ(ixdp2x01_init_irq)
-       INITTIME(ixdp2x01_init_time)
+       .timer          = &ixdp2x01_timer,
        INIT_MACHINE(ixdp2x01_init_machine)
 MACHINE_END
 #endif
@@ -373,7 +392,7 @@ MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
        BOOT_PARAMS(0x00000100)
        MAPIO(ixdp2x01_map_io)
        INITIRQ(ixdp2x01_init_irq)
-       INITTIME(ixdp2x01_init_time)
+       .timer          = &ixdp2x01_timer,
        INIT_MACHINE(ixdp2x01_init_machine)
 MACHINE_END
 #endif
index d08cebe..7e6c588 100644 (file)
@@ -148,13 +148,13 @@ int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_re
        cli();
        temp = *(IXP2000_PCI_CONTROL);
        if (temp & ((1 << 8) | (1 << 5))) {
-               *(IXP2000_PCI_CONTROL) = temp;
+               ixp2000_reg_write(IXP2000_PCI_CONTROL, temp);
        }
 
        temp = *(IXP2000_PCI_CMDSTAT);
        if (temp & (1 << 29)) {
                while (temp & (1 << 29)) {      
-                       *(IXP2000_PCI_CMDSTAT) = temp;
+                       ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
                        temp = *(IXP2000_PCI_CMDSTAT);
                }
        }
@@ -178,13 +178,13 @@ clear_master_aborts(void)
        cli();
        temp = *(IXP2000_PCI_CONTROL);
        if (temp & ((1 << 8) | (1 << 5))) {     
-               *(IXP2000_PCI_CONTROL) = temp;
+               ixp2000_reg_write(IXP2000_PCI_CONTROL, temp);
        }
 
        temp = *(IXP2000_PCI_CMDSTAT);
        if (temp & (1 << 29)) {
                while (temp & (1 << 29)) {
-                       *(IXP2000_PCI_CMDSTAT) = temp;
+                       ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
                        temp = *(IXP2000_PCI_CMDSTAT);
                }
        }
index 46b72e1..79bf95e 100644 (file)
@@ -29,6 +29,13 @@ config ARCH_IXDP425
          IXDP425 Development Platform (Also known as Richfield).  
          For more information on this platform, see Documentation/arm/IXP4xx.
 
+config MACH_IXDPG425
+       bool "IXDPG425"
+       help
+         Say 'Y' here if you want your kernel to support Intel's
+         IXDPG425 Development Platform (Also known as Montajade).
+         For more information on this platform, see Documentation/arm/IXP4xx.
+
 #
 # IXCDP1100 is the exact same HW as IXDP425, but with a different machine 
 # number from the bootloader due to marketing monkeys, so we just enable it 
index f656397..465e6f4 100644 (file)
@@ -5,6 +5,7 @@
 obj-y  += common.o common-pci.o 
 
 obj-$(CONFIG_ARCH_IXDP4XX)     += ixdp425-pci.o ixdp425-setup.o
+obj-$(CONFIG_MACH_IXDPG425)    += ixdpg425-pci.o coyote-setup.o
 obj-$(CONFIG_ARCH_ADI_COYOTE)  += coyote-pci.o coyote-setup.o
 obj-$(CONFIG_ARCH_PRPMC1100)   += prpmc1100-pci.o prpmc1100-setup.o
 
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
+
index 6645218..69486bd 100644 (file)
@@ -33,7 +33,6 @@
 #include <asm/system.h>
 #include <asm/mach/pci.h>
 #include <asm/hardware.h>
-#include <asm/sizes.h>
 
 
 /*
@@ -239,9 +238,10 @@ static u32 byte_lane_enable_bits(u32 n, int size)
        return 0xffffffff;
 }
 
-static int read_config(u8 bus_num, u16 devfn, int where, int size, u32 *value)
+static int ixp4xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
 {
        u32 n, byte_enables, addr, data;
+       u8 bus_num = bus->number;
 
        pr_debug("read_config from %d size %d dev %d:%d:%d\n", where, size,
                bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn));
@@ -261,9 +261,10 @@ static int read_config(u8 bus_num, u16 devfn, int where, int size, u32 *value)
        return PCIBIOS_SUCCESSFUL;
 }
 
-static int write_config(u8 bus_num, u16 devfn, int where, int size, u32 value)
+static int ixp4xx_pci_write_config(struct pci_bus *bus,  unsigned int devfn, int where, int size, u32 value)
 {
        u32 n, byte_enables, addr, data;
+       u8 bus_num = bus->number;
 
        pr_debug("write_config_byte %#x to %d size %d dev %d:%d:%d\n", value, where,
                size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn));
@@ -281,31 +282,11 @@ static int write_config(u8 bus_num, u16 devfn, int where, int size, u32 value)
        return PCIBIOS_SUCCESSFUL;
 }
 
-/*
- *     Generalized PCI config access functions.
- */
-static int ixp4xx_read_config(struct pci_bus *bus, unsigned int devfn,
-       int where, int size, u32 *value)
-{
-       if (bus->number && !PCI_SLOT(devfn))
-               return local_read_config(where, size, value);
-       return read_config(bus->number, devfn, where, size, value);
-}
-
-static int ixp4xx_write_config(struct pci_bus *bus, unsigned int devfn,
-       int where, int size, u32 value)
-{
-       if (bus->number && !PCI_SLOT(devfn))
-               return local_write_config(where, size, value);
-       return write_config(bus->number, devfn, where, size, value);
-}
-
 struct pci_ops ixp4xx_ops = {
-       .read =  ixp4xx_read_config,
-       .write = ixp4xx_write_config,
+       .read =  ixp4xx_pci_read_config,
+       .write = ixp4xx_pci_write_config,
 };
 
-
 /*
  * PCI abort handler
  */
index 24ffa32..3e24140 100644 (file)
@@ -221,16 +221,20 @@ static unsigned long ixp4xx_gettimeoffset(void)
 
 static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+       write_seqlock(&xtime_lock);
+
        /* Clear Pending Interrupt by writing '1' to it */
        *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
 
        /*
         * Catch up with the real idea of time
         */
-       do {    
+       while ((*IXP4XX_OSTS - last_jiffy_time) > LATCH) {
                timer_tick(regs);
                last_jiffy_time += LATCH;
-       } while((*IXP4XX_OSTS - last_jiffy_time) > LATCH);
+       }
+
+       write_sequnlock(&xtime_lock);
 
        return IRQ_HANDLED;
 }
@@ -241,10 +245,8 @@ static struct irqaction ixp4xx_timer_irq = {
        .handler        = ixp4xx_timer_interrupt
 };
 
-void __init ixp4xx_init_time(void)
+static void __init ixp4xx_timer_init(void)
 {
-       gettimeoffset = ixp4xx_gettimeoffset;
-
        /* Clear Pending Interrupt by writing '1' to it */
        *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
 
@@ -259,4 +261,7 @@ void __init ixp4xx_init_time(void)
        setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
 }
 
-
+struct sys_timer ixp4xx_timer = {
+       .init           = ixp4xx_timer_init,
+       .offset         = ixp4xx_gettimeoffset,
+};
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);
index 01e98fd..199e454 100644 (file)
@@ -88,7 +88,7 @@ MACHINE_START(PRPMC1100, "Motorola PrPMC1100")
                 IXP4XX_PERIPHERAL_BASE_VIRT)
         MAPIO(prpmc1100_map_io)
         INITIRQ(ixp4xx_init_irq)
-       INITTIME(ixp4xx_init_time)
+       .timer          = &ixp4xx_timer,
         BOOT_PARAMS(0x0100)
        INIT_MACHINE(prpmc1100_init)
 MACHINE_END
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);
index f4943ca..51e1c81 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/leds.h>
 
 #include <asm/mach/time.h>
+#include "common.h"
 
 #if HZ < 100
 # define TIMER_CONTROL TIMER_CONTROL2
 static irqreturn_t
 lh7a40x_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+       write_seqlock(&xtime_lock);
+
        TIMER_EOI = 0;
        timer_tick(regs);
 
+       write_sequnlock(&xtime_lock);
+
        return IRQ_HANDLED;
 }
 
@@ -52,7 +57,7 @@ static struct irqaction lh7a40x_timer_irq = {
        .handler        = lh7a40x_timer_interrupt
 };
 
-void __init lh7a40x_init_time(void)
+static void __init lh7a40x_timer_init(void)
 {
                                /* Stop/disable all timers */
        TIMER_CONTROL1 = 0;
@@ -65,3 +70,6 @@ void __init lh7a40x_init_time(void)
        TIMER_CONTROL = TIMER_MODE;
 }
 
+struct sys_timer lh7a40x_timer = {
+       .init           = &lh7a40x_timer_init,
+};
index 9fb70d5..f8d265d 100644 (file)
@@ -5,58 +5,56 @@ menu "TI OMAP Implementations"
 comment "OMAP Core Type"
 
 config ARCH_OMAP730
+       depends on ARCH_OMAP
        bool "OMAP730 Based System"
-       select CPU_ARM926T
+       select ARCH_OMAP_OTG
 
 config ARCH_OMAP1510
+       depends on ARCH_OMAP
        default y
        bool "OMAP1510 Based System"
-       select CPU_ARM925T
-       select CPU_DCACHE_WRITETHROUGH
 
-config ARCH_OMAP1610
-       bool "OMAP1610 Based System"
-       select CPU_ARM926T
+config ARCH_OMAP16XX
+       depends on ARCH_OMAP
+       bool "OMAP16XX Based System"
+       select ARCH_OMAP_OTG
 
-config ARCH_OMAP5912
-       bool "OMAP5912 Based System"
-       select CPU_ARM926T
+config ARCH_OMAP_OTG
+       bool
 
 comment "OMAP Board Type"
 
 config MACH_OMAP_INNOVATOR
        bool "TI Innovator"
-       default y
-       depends on ARCH_OMAP1510 || ARCH_OMAP1610
+       depends on ARCH_OMAP1510 || ARCH_OMAP16XX
        help
           TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
           have such a board.
 
 config MACH_OMAP_H2
        bool "TI H2 Support"
-       depends on ARCH_OMAP1610
-        select MACH_OMAP_INNOVATOR
+       depends on ARCH_OMAP16XX
        help
-         TI OMAP 1610 H2 board support. Say Y here if you have such
+         TI OMAP 1610/1611B H2 board support. Say Y here if you have such
          a board.
 
 config MACH_OMAP_H3
        bool "TI H3 Support"
-       depends on ARCH_OMAP1610
+       depends on ARCH_OMAP16XX
        help
-         TI OMAP 1610 H3 board support. Say Y here if you have such
+         TI OMAP 1710 H3 board support. Say Y here if you have such
          a board.
 
 config MACH_OMAP_H4
        bool "TI H4 Support"
-       depends on ARCH_OMAP1610
+       depends on ARCH_OMAP16XX
        help
          TI OMAP 1610 H4 board support. Say Y here if you have such
          a board.
 
 config MACH_OMAP_OSK
        bool "TI OSK Support"
-       depends on ARCH_OMAP5912
+       depends on ARCH_OMAP16XX
        help
          TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
           if you have such a board.
@@ -64,19 +62,16 @@ config MACH_OMAP_OSK
 config MACH_OMAP_PERSEUS2
        bool "TI Perseus2"
        depends on ARCH_OMAP730
-       select LEDS
-       select LEDS_TIMER
-       select LEDS_CPU
        help
          Support for TI OMAP 730 Perseus2 board. Say Y here if you have such
          a board.
 
 config MACH_OMAP_GENERIC
        bool "Generic OMAP board"
-       depends on ARCH_OMAP1510 || ARCH_OMAP1610
+       depends on ARCH_OMAP1510 || ARCH_OMAP16XX
        help
-          Support for generic OMAP-1510 or 1610 board with no
-          FPGA. Can be used as template for porting Linux to
+          Support for generic OMAP-1510, 1610 or 1710 board with
+          no FPGA. Can be used as template for porting Linux to
           custom OMAP boards. Say Y here if you have a custom
           board.
 
@@ -84,6 +79,7 @@ comment "OMAP Feature Selections"
 
 #config OMAP_BOOT_TAG
 #      bool "OMAP bootloader information passing"
+#        depends on ARCH_OMAP
 #        default n
 #        help
 #          Say Y, if you have a bootloader which passes information
@@ -91,6 +87,7 @@ comment "OMAP Feature Selections"
 
 config OMAP_MUX
        bool "OMAP multiplexing support"
+        depends on ARCH_OMAP
        default y
         help
           Pin multiplexing support for OMAP boards. If your bootloader
@@ -106,8 +103,18 @@ config OMAP_MUX_DEBUG
           This is useful if you want to find out the correct values of the
           multiplexing registers.
 
+config OMAP_MUX_WARNINGS
+       bool "Warn about pins the bootloader didn't set up"
+        depends on OMAP_MUX
+        default y
+        help
+         Choose Y here to warn whenever driver initialization logic needs
+         to change the pin multiplexing setup.  When there are no warnings
+         printed, it's safe to deselect OMAP_MUX for your product.
+
 choice
        prompt "Low-level debug console UART"
+       depends on ARCH_OMAP
        default OMAP_LL_DEBUG_UART1
 
 config OMAP_LL_DEBUG_UART1
@@ -129,7 +136,7 @@ config OMAP_ARM_195MHZ
 
 config OMAP_ARM_192MHZ
        bool "OMAP ARM 192 MHz CPU"
-       depends on ARCH_OMAP1610 || ARCH_OMAP5912
+       depends on ARCH_OMAP16XX
        help
           Enable 192MHz clock for OMAP CPU. If unsure, say N.
 
@@ -141,26 +148,26 @@ config OMAP_ARM_182MHZ
 
 config OMAP_ARM_168MHZ
        bool "OMAP ARM 168 MHz CPU"
-       depends on ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_OMAP730 || ARCH_OMAP5912
+       depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
        help
           Enable 168MHz clock for OMAP CPU. If unsure, say N.
 
 config OMAP_ARM_120MHZ
        bool "OMAP ARM 120 MHz CPU"
-       depends on ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_OMAP730
+       depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
        help
           Enable 120MHz clock for OMAP CPU. If unsure, say N.
 
 config OMAP_ARM_60MHZ
        bool "OMAP ARM 60 MHz CPU"
-       depends on ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_OMAP730
+       depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
         default y
        help
           Enable 60MHz clock for OMAP CPU. If unsure, say Y.
 
 config OMAP_ARM_30MHZ
        bool "OMAP ARM 30 MHz CPU"
-       depends on ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_OMAP730
+       depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
        help
           Enable 30MHz clock for OMAP CPU. If unsure, say N.
 
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
+
index 1441089..f273b8d 100644 (file)
 #include <asm/arch/clocks.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/usb.h>
+#include <asm/arch/serial.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 int __initdata h2_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
 
 static struct resource h2_smc91x_resources[] = {
        [0] = {
@@ -80,15 +75,22 @@ static struct omap_usb_config h2_usb_config __initdata = {
        .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) */
+       /* needs OTG cable, or NONSTANDARD (B-to-MiniB) */
        .hmc_mode       = 20,   // 1:dev|otg(off) 1:host 2:disabled
 #endif
 
        .pins[1]        = 3,
 };
 
+static struct omap_mmc_config h2_mmc_config __initdata = {
+       .mmc_blocks             = 1,
+       .mmc1_power_pin         = -1,   /* tps65010 gpio3 */
+       .mmc1_switch_pin        = OMAP_MPUIO(1),
+};
+
 static struct omap_board_config_kernel h2_config[] = {
        { OMAP_TAG_USB,           &h2_usb_config },
+       { OMAP_TAG_MMC,           &h2_mmc_config },
 };
 
 static void __init h2_init(void)
@@ -101,7 +103,7 @@ static void __init h2_init(void)
 static void __init h2_map_io(void)
 {
        omap_map_io();
-       iotable_init(h2_io_desc, ARRAY_SIZE(h2_io_desc));
+       omap_serial_init(h2_serial_ports);
 }
 
 MACHINE_START(OMAP_H2, "TI-H2")
@@ -111,5 +113,5 @@ MACHINE_START(OMAP_H2, "TI-H2")
        MAPIO(h2_map_io)
        INITIRQ(h2_init_irq)
        INIT_MACHINE(h2_init)
-       INITTIME(omap_init_time)
+       .timer          = &omap_timer,
 MACHINE_END
index d573b0c..301f227 100644 (file)
 #include <asm/arch/irqs.h>
 #include <asm/arch/gpio.h>
 #include <asm/mach-types.h>
-#include "common.h"
+#include <asm/arch/serial.h>
 
-extern void __init omap_init_time(void);
+#include "common.h"
 
 void h3_init_irq(void)
 {
        omap_init_irq();
 }
 
+static int __initdata h3_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+
 static struct resource smc91x_resources[] = {
        [0] = {
                .start  = OMAP1710_ETHR_START,          /* Physical */
@@ -68,15 +70,10 @@ 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));
+       omap_serial_init(h3_serial_ports);
 }
 
 MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
@@ -86,5 +83,5 @@ MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
        MAPIO(h3_map_io)
        INITIRQ(h3_init_irq)
        INIT_MACHINE(h3_init)
-       INITTIME(omap_init_time)
+       .timer          = &omap_timer,
 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
index 17d82a7..91d9caa 100644 (file)
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
 
 #include <asm/hardware.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/mach/map.h>
-#include <asm/arch/clocks.h>
-#include <asm/arch/board.h>
+#include <asm/hardware/clock.h>
 #include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+#include <asm/arch/serial.h>
+
+
+#include "clock.h"
+
+#define DEBUG 1
+
+struct omap_id {
+       u16     jtag_id;        /* Used to determine OMAP type */
+       u8      die_rev;        /* Processor revision */
+       u32     omap_id;        /* OMAP revision */
+       u32     type;           /* Cpu id bits [31:08], cpu class bits [07:00] */
+};
+
+/* Register values to detect the OMAP version */
+static struct omap_id omap_ids[] __initdata = {
+       { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
+       { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
+       { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
+       { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000},
+       { .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000},
+       { .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00},
+       { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00},
+       { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+       { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+       { .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000},
+       { .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00},
+       { .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00},
+       { .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300},
+       { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300},
+       { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300},
+       { .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000},
+       { .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000},
+       { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
+};
 
 /*
- * ----------------------------------------------------------------------------
- * OMAP revision check
- *
- * Since we use the cpu_is_omapnnnn() macros, there's a chance that a board
- * switches to an updated core. We want to print out the OMAP revision early.
- *
- * We use the system_serial registers for the revision information so we
- * can see it in /proc/cpuinfo.
- *
- * If the OMAP detection gets more complicated, we may want to expand this
- * to store the OMAP version and replace the current cpu_is_omapnnnn() macros.
- *
- * ----------------------------------------------------------------------------
+ * Get OMAP type from PROD_ID.
+ * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
+ * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense.
+ * Undocumented register in TEST BLOCK is used as fallback; This seems to
+ * work on 1510, 1610 & 1710. The official way hopefully will work in future
+ * processors.
+ */
+static u16 __init omap_get_jtag_id(void)
+{
+       u32 prod_id, omap_id;
+
+       prod_id = omap_readl(OMAP_PRODUCTION_ID_1);
+       omap_id = omap_readl(OMAP32_ID_1);
+
+       /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */
+       if (((prod_id >> 20) == 0) || (prod_id == omap_id))
+               prod_id = 0;
+       else
+               prod_id &= 0xffff;
+
+       if (prod_id)
+               return prod_id;
+
+       /* Use OMAP32_ID_1 as fallback */
+       prod_id = ((omap_id >> 12) & 0xffff);
+
+       return prod_id;
+}
+
+/*
+ * Get OMAP revision from DIE_REV.
+ * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID.
+ * Undocumented register in the TEST BLOCK is used as fallback.
+ * REVISIT: This does not seem to work on 1510
  */
+static u8 __init omap_get_die_rev(void)
+{
+       u32 die_rev;
+
+       die_rev = omap_readl(OMAP_DIE_ID_1);
+
+       /* Check for broken OMAP_DIE_ID on early 1710 */
+       if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id())
+               die_rev = 0;
+
+       die_rev = (die_rev >> 17) & 0xf;
+       if (die_rev)
+               return die_rev;
+
+       die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf;
+
+       return die_rev;
+}
+
 static void __init omap_check_revision(void)
 {
-       system_serial_high = omap_readl(OMAP_ID_BASE);
-       system_serial_low = OMAP_ID_REG;
-       system_rev = (OMAP_ID_REG >> ID_SHIFT) & ID_MASK;
-
-       printk("OMAP revision: %d.%d (0x%08x) id: 0x%08x detected as OMAP-",
-              (system_serial_high >> 20) & 0xf,
-              (system_serial_high >> 16) & 0xf,
-              system_serial_high, system_serial_low);
-
-       switch (system_rev) {
-       case OMAP_ID_730:
-               printk("730\n");
-               system_rev = 0x730;
-               break;
-       case OMAP_ID_1510:
-               printk("1510\n");
-               system_rev = 0x1510;
+       int i;
+       u16 jtag_id;
+       u8 die_rev;
+       u32 omap_id;
+       u8 cpu_type;
+
+       jtag_id = omap_get_jtag_id();
+       die_rev = omap_get_die_rev();
+       omap_id = omap_readl(OMAP32_ID_0);
+
+#ifdef DEBUG
+       printk("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
+       printk("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
+               omap_readl(OMAP_DIE_ID_1),
+              (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
+       printk("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0));
+       printk("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
+               omap_readl(OMAP_PRODUCTION_ID_1),
+               omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
+       printk("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
+       printk("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
+       printk("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
+#endif
+
+       system_serial_high = omap_readl(OMAP_DIE_ID_0);
+       system_serial_low = omap_readl(OMAP_DIE_ID_1);
+
+       /* First check only the major version in a safe way */
+       for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+               if (jtag_id == (omap_ids[i].jtag_id)) {
+                       system_rev = omap_ids[i].type;
+                       break;
+               }
+       }
+
+       /* Check if we can find the die revision */
+       for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+               if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
+                       system_rev = omap_ids[i].type;
+                       break;
+               }
+       }
+
+       /* Finally check also the omap_id */
+       for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+               if (jtag_id == omap_ids[i].jtag_id
+                   && die_rev == omap_ids[i].die_rev
+                   && omap_id == omap_ids[i].omap_id) {
+                       system_rev = omap_ids[i].type;
+                       break;
+               }
+       }
+
+       /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
+       cpu_type = system_rev >> 24;
+
+       switch (cpu_type) {
+       case 0x07:
+               system_rev |= 0x07;
                break;
-       case OMAP_ID_1610:
-               printk("1610\n");
-               system_rev = 0x1610;
+       case 0x15:
+               system_rev |= 0x15;
                break;
-       case OMAP_ID_1710:
-               printk("1710\n");
-               system_rev = 0x1710;
+       case 0x16:
+       case 0x17:
+               system_rev |= 0x16;
                break;
-       case OMAP_ID_5912:
-               printk("5912/1611B\n");
-               system_rev = 0x5912;
+       case 0x24:
+               system_rev |= 0x24;
                break;
        default:
-               printk("unknown, please add support!\n");
+               printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type);
        }
+
+       printk("OMAP%04x", system_rev >> 16);
+       if ((system_rev >> 8) & 0xff)
+               printk("%x", (system_rev >> 8) & 0xff);
+       printk(" revision %i handled as %02xxx id: %08x%08x\n",
+              die_rev, system_rev & 0xff, system_serial_low,
+              system_serial_high);
 }
 
 /*
@@ -104,25 +234,23 @@ static struct map_desc omap1510_io_desc[] __initdata = {
 };
 #endif
 
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+#if defined(CONFIG_ARCH_OMAP16XX)
 static struct map_desc omap1610_io_desc[] __initdata = {
- { OMAP1610_DSP_BASE,    OMAP1610_DSP_START,    OMAP1610_DSP_SIZE,    MT_DEVICE },
- { OMAP1610_DSPREG_BASE, OMAP1610_DSPREG_START, OMAP1610_DSPREG_SIZE, MT_DEVICE },
- { OMAP1610_SRAM_BASE,   OMAP1610_SRAM_START,   OMAP1610_SRAM_SIZE,   MT_DEVICE }
+ { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
+ { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
+ { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP1610_SRAM_SIZE,   MT_DEVICE }
 };
-#endif
 
-#ifdef CONFIG_ARCH_OMAP5912
 static struct map_desc omap5912_io_desc[] __initdata = {
- { OMAP5912_DSP_BASE,    OMAP5912_DSP_START,    OMAP5912_DSP_SIZE,    MT_DEVICE },
- { OMAP5912_DSPREG_BASE, OMAP5912_DSPREG_START, OMAP5912_DSPREG_SIZE, MT_DEVICE },
+ { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
+ { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
 /*
  * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page
  * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped.
  * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte
  * can be used.
  */
- { OMAP5912_SRAM_BASE,   OMAP5912_SRAM_START,   OMAP5912_SRAM_SIZE + 0x800,   MT_DEVICE }
+ { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP5912_SRAM_SIZE + 0x800,   MT_DEVICE }
 };
 #endif
 
@@ -137,6 +265,9 @@ static void __init _omap_map_io(void)
        iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc));
        omap_check_revision();
 
+       /* clear BM to canonicalize CS0 (not CS3) at 0000:0000 */
+       omap_writel(omap_readl(EMIFS_CONFIG) & 0x0d, EMIFS_CONFIG);
+
 #ifdef CONFIG_ARCH_OMAP730
        if (cpu_is_omap730()) {
                iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
@@ -147,12 +278,10 @@ static void __init _omap_map_io(void)
                iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
        }
 #endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+#if defined(CONFIG_ARCH_OMAP16XX)
        if (cpu_is_omap1610() || cpu_is_omap1710()) {
                iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc));
        }
-#endif
-#ifdef CONFIG_ARCH_OMAP5912
        if (cpu_is_omap5912()) {
                iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc));
        }
@@ -166,7 +295,7 @@ static void __init _omap_map_io(void)
 
        /* Must init clocks early to assure that timer interrupt works
         */
-       init_ck();
+       clk_init();
 }
 
 /*
@@ -178,26 +307,173 @@ void omap_map_io(void)
                _omap_map_io();
 }
 
+static inline unsigned int omap_serial_in(struct plat_serial8250_port *up, 
+                                         int offset)
+{
+       offset <<= up->regshift;
+       return (unsigned int)__raw_readb(up->membase + offset);
+}
+
+static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset, 
+                                   int value)
+{
+       offset <<= p->regshift;
+       __raw_writeb(value, p->membase + offset);
+}
+
+/*
+ * Internal UARTs need to be initialized for the 8250 autoconfig to work
+ * properly.
+ */
+static void __init omap_serial_reset(struct plat_serial8250_port *p)
+{
+       omap_serial_outp(p, UART_OMAP_MDR1, 0x07); /* disable UART */
+       omap_serial_outp(p, UART_OMAP_MDR1, 0x00); /* enable UART */
+
+       if (!cpu_is_omap1510()) {
+               omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
+               while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
+       }
+}
+
+static struct plat_serial8250_port serial_platform_data[] = {
+       {
+               .membase        = (char*)IO_ADDRESS(OMAP_UART1_BASE),
+               .mapbase        = (unsigned long)OMAP_UART1_BASE,
+               .irq            = INT_UART1,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = OMAP16XX_BASE_BAUD * 16,
+       },
+       {
+               .membase        = (char*)IO_ADDRESS(OMAP_UART2_BASE),
+               .mapbase        = (unsigned long)OMAP_UART2_BASE,
+               .irq            = INT_UART2,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = OMAP16XX_BASE_BAUD * 16,
+       },
+       {
+               .membase        = (char*)IO_ADDRESS(OMAP_UART3_BASE),
+               .mapbase        = (unsigned long)OMAP_UART3_BASE,
+               .irq            = INT_UART3,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = OMAP16XX_BASE_BAUD * 16,
+       },
+       { },
+};
+
+static struct platform_device serial_device = {
+       .name                   = "serial8250",
+       .id                     = 0,
+       .dev                    = {
+               .platform_data  = serial_platform_data,
+       },
+};
+
+/*
+ * Note that on Innovator-1510 UART2 pins conflict with USB2.
+ * By default UART2 does not work on Innovator-1510 if you have
+ * USB OHCI enabled. To use UART2, you must disable USB2 first.
+ */
+void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
+{
+       int i;
+
+       if (cpu_is_omap730()) {
+               serial_platform_data[0].regshift = 0;
+               serial_platform_data[1].regshift = 0;
+               serial_platform_data[0].irq = INT_730_UART_MODEM_1;
+               serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
+       }
+
+       if (cpu_is_omap1510()) {
+               serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
+               serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
+               serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
+       }
+
+       for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+               unsigned char reg;
+
+               if (ports[i] == 0) {
+                       serial_platform_data[i].membase = 0;
+                       serial_platform_data[i].mapbase = 0;
+                       continue;
+               }
+
+               switch (i) {
+               case 0:
+                       if (cpu_is_omap1510()) {
+                               omap_cfg_reg(UART1_TX);
+                               omap_cfg_reg(UART1_RTS);
+                               if (machine_is_omap_innovator()) {
+                                       reg = fpga_read(OMAP1510_FPGA_POWER);
+                                       reg |= OMAP1510_FPGA_PCR_COM1_EN;
+                                       fpga_write(reg, OMAP1510_FPGA_POWER);
+                                       udelay(10);
+                               }
+                       }
+                       break;
+               case 1:
+                       if (cpu_is_omap1510()) {
+                               omap_cfg_reg(UART2_TX);
+                               omap_cfg_reg(UART2_RTS);
+                               if (machine_is_omap_innovator()) {
+                                       reg = fpga_read(OMAP1510_FPGA_POWER);
+                                       reg |= OMAP1510_FPGA_PCR_COM2_EN;
+                                       fpga_write(reg, OMAP1510_FPGA_POWER);
+                                       udelay(10);
+                               }
+                       }
+                       break;
+               case 2:
+                       if (cpu_is_omap1510()) {
+                               omap_cfg_reg(UART3_TX);
+                               omap_cfg_reg(UART3_RX);
+                       }
+                       break;
+               }
+               omap_serial_reset(&serial_platform_data[i]);
+       }
+}
+
+static int __init omap_init(void)
+{
+       return platform_device_register(&serial_device);
+}
+arch_initcall(omap_init);
+
+#define NO_LENGTH_CHECK 0xffffffff
+
 extern int omap_bootloader_tag_len;
 extern u8 omap_bootloader_tag[];
 
 struct omap_board_config_kernel *omap_board_config;
 int omap_board_config_size = 0;
 
-const void *__omap_get_config(u16 tag, size_t len)
+static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
 {
-       struct omap_board_config_entry *info = NULL;
        struct omap_board_config_kernel *kinfo = NULL;
        int i;
 
 #ifdef CONFIG_OMAP_BOOT_TAG
+       struct omap_board_config_entry *info = NULL;
+
        if (omap_bootloader_tag_len > 4)
                info = (struct omap_board_config_entry *) omap_bootloader_tag;
        while (info != NULL) {
                u8 *next;
 
-               if (info->tag == tag)
-                       break;
+               if (info->tag == tag) {
+                       if (skip == 0)
+                               break;
+                       skip--;
+               }
 
                next = (u8 *) info + sizeof(*info) + info->len;
                if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
@@ -208,11 +484,13 @@ const void *__omap_get_config(u16 tag, size_t len)
        if (info != NULL) {
                /* Check the length as a lame attempt to check for
                 * binary inconsistancy. */
-               if (info->len != len) {
+               if (len != NO_LENGTH_CHECK && info->len != len) {
                        printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
                               tag, len, info->len);
                        return NULL;
                }
+               if (len_out != NULL)
+                       *len_out = info->len;
                return info->data;
        }
 #endif
@@ -228,8 +506,19 @@ const void *__omap_get_config(u16 tag, size_t len)
                return NULL;
        return kinfo->data;
 }
+
+const void *__omap_get_config(u16 tag, size_t len, int nr)
+{
+        return get_config(tag, len, nr, NULL);
+}
 EXPORT_SYMBOL(__omap_get_config);
 
+const void *omap_get_var_config(u16 tag, size_t *len)
+{
+        return get_config(tag, NO_LENGTH_CHECK, 0, len);
+}
+EXPORT_SYMBOL(omap_get_var_config);
+
 static int __init omap_add_serial_console(void)
 {
        const struct omap_uart_config *info;
index d334395..7c4ad77 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/wait.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
+#include <linux/err.h>
 
 #include <asm/delay.h>
 #include <asm/io.h>
@@ -28,6 +29,8 @@
 #include <asm/arch/irqs.h>
 #include <asm/arch/mcbsp.h>
 
+#include <asm/hardware/clock.h>
+
 #ifdef CONFIG_MCBSP_DEBUG
 #define DBG(x...)      printk(x)
 #else
@@ -61,6 +64,8 @@ struct omap_mcbsp {
 };
 
 static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
+static struct clk *mcbsp_dsp_ck = 0;
+static struct clk *mcbsp_api_ck = 0;
 
 
 static void omap_mcbsp_dump_reg(u8 id)
@@ -153,8 +158,8 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config
        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, MCR2, config->mcr2);
+       OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1);
        OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0);
 }
 
@@ -181,6 +186,7 @@ static int omap_mcbsp_check(unsigned int id)
        return -1;
 }
 
+#define EN_XORPCK              1
 #define DSP_RSTCT2              0xe1008014
 
 static void omap_mcbsp_dsp_request(void)
@@ -188,10 +194,8 @@ 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);
+               clk_enable(mcbsp_dsp_ck);
+               clk_enable(mcbsp_api_ck);
 
                /* enable 12MHz clock to mcbsp 1 & 3 */
                __raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK),
@@ -588,7 +592,7 @@ static const struct omap_mcbsp_info mcbsp_1510[] = {
 };
 #endif
 
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+#if defined(CONFIG_ARCH_OMAP16XX)
 static const struct omap_mcbsp_info mcbsp_1610[] = {
        [0] = { .virt_base = OMAP1610_MCBSP1_BASE,
                .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
@@ -614,6 +618,18 @@ static int __init omap_mcbsp_init(void)
        static const struct omap_mcbsp_info *mcbsp_info;
 
        printk("Initializing OMAP McBSP system\n");
+
+       mcbsp_dsp_ck = clk_get(0, "dsp_ck");
+       if (IS_ERR(mcbsp_dsp_ck)) {
+               printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n");
+               return PTR_ERR(mcbsp_dsp_ck);
+       }
+       mcbsp_api_ck = clk_get(0, "api_ck");
+       if (IS_ERR(mcbsp_dsp_ck)) {
+               printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n");
+               return PTR_ERR(mcbsp_api_ck);
+       }
+
 #ifdef CONFIG_ARCH_OMAP730
        if (cpu_is_omap730()) {
                mcbsp_info = mcbsp_730;
@@ -626,7 +642,7 @@ static int __init omap_mcbsp_init(void)
                mcbsp_count = ARRAY_SIZE(mcbsp_1510);
        }
 #endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+#if defined(CONFIG_ARCH_OMAP16XX)
        if (cpu_is_omap1610() || cpu_is_omap1710()) {
                mcbsp_info = mcbsp_1610;
                mcbsp_count = ARRAY_SIZE(mcbsp_1610);
index 70665df..e377139 100644 (file)
 #define __MUX_C__
 #include <asm/arch/mux.h>
 
+#ifdef CONFIG_OMAP_MUX
+
 /*
  * Sets the Omap MUX and PULL_DWN registers based on the table
  */
-int omap_cfg_reg(const reg_cfg_t reg_cfg)
+int __init_or_module
+omap_cfg_reg(const reg_cfg_t reg_cfg)
 {
-#ifdef CONFIG_OMAP_MUX
        static spinlock_t mux_spin_lock = SPIN_LOCK_UNLOCKED;
 
        unsigned long flags;
        reg_cfg_set *cfg;
        unsigned int reg_orig = 0, reg = 0, pu_pd_orig = 0, pu_pd = 0,
                pull_orig = 0, pull = 0;
+       unsigned int mask, warn = 0;
+
+       if (reg_cfg > ARRAY_SIZE(reg_cfg_table)) {
+               printk(KERN_ERR "MUX: reg_cfg %d\n", reg_cfg);
+               return -EINVAL;
+       }
 
        cfg = &reg_cfg_table[reg_cfg];
 
@@ -56,12 +64,20 @@ int omap_cfg_reg(const reg_cfg_t reg_cfg)
 
        /* Check the mux register in question */
        if (cfg->mux_reg) {
+               unsigned        tmp1, tmp2;
+
                reg_orig = omap_readl(cfg->mux_reg);
 
                /* The mux registers always seem to be 3 bits long */
-               reg = reg_orig & ~(0x7 << cfg->mask_offset);
+               mask = (0x7 << cfg->mask_offset);
+               tmp1 = reg_orig & mask;
+               reg = reg_orig & ~mask;
+
+               tmp2 = (cfg->mask << cfg->mask_offset);
+               reg |= tmp2;
 
-               reg |= (cfg->mask << cfg->mask_offset);
+               if (tmp1 != tmp2)
+                       warn = 1;
 
                omap_writel(reg, cfg->mux_reg);
        }
@@ -70,12 +86,18 @@ int omap_cfg_reg(const reg_cfg_t reg_cfg)
        if (!cpu_is_omap1510()) {
                if (cfg->pu_pd_reg && cfg->pull_val) {
                        pu_pd_orig = omap_readl(cfg->pu_pd_reg);
+                       mask = 1 << cfg->pull_bit;
+
                        if (cfg->pu_pd_val) {
+                               if (!(pu_pd_orig & mask))
+                                       warn = 1;
                                /* Use pull up */
-                               pu_pd = pu_pd_orig | (1 << cfg->pull_bit);
+                               pu_pd = pu_pd_orig | mask;
                        } else {
+                               if (pu_pd_orig & mask)
+                                       warn = 1;
                                /* Use pull down */
-                               pu_pd = pu_pd_orig & ~(1 << cfg->pull_bit);
+                               pu_pd = pu_pd_orig & ~mask;
                        }
                        omap_writel(pu_pd, cfg->pu_pd_reg);
                }
@@ -84,21 +106,32 @@ int omap_cfg_reg(const reg_cfg_t reg_cfg)
        /* Check for an associated pull down register */
        if (cfg->pull_reg) {
                pull_orig = omap_readl(cfg->pull_reg);
+               mask = 1 << cfg->pull_bit;
 
                if (cfg->pull_val) {
+                       if (pull_orig & mask)
+                               warn = 1;
                        /* Low bit = pull enabled */
-                       pull = pull_orig & ~(1 << cfg->pull_bit);
+                       pull = pull_orig & ~mask;
                } else {
+                       if (!(pull_orig & mask))
+                               warn = 1;
                        /* High bit = pull disabled */
-                       pull = pull_orig | (1 << cfg->pull_bit);
+                       pull = pull_orig | mask;
                }
 
                omap_writel(pull, cfg->pull_reg);
        }
 
+       if (warn) {
+#ifdef CONFIG_OMAP_MUX_WARNINGS
+               printk(KERN_WARNING "MUX: initialized %s\n", cfg->name);
+#endif
+       }
+
 #ifdef CONFIG_OMAP_MUX_DEBUG
-       if (cfg->debug) {
-               printk("Omap: Setting register %s\n", cfg->name);
+       if (cfg->debug || warn) {
+               printk("MUX: Setting register %s\n", cfg->name);
                printk("      %s (0x%08x) = 0x%08x -> 0x%08x\n",
                       cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
 
@@ -118,8 +151,13 @@ int omap_cfg_reg(const reg_cfg_t reg_cfg)
 
        spin_unlock_irqrestore(&mux_spin_lock, flags);
 
-#endif
+#ifdef CONFIG_OMAP_MUX_ERRORS
+       return warn ? -ETXTBSY : 0;
+#else
        return 0;
+#endif
 }
 
 EXPORT_SYMBOL(omap_cfg_reg);
+
+#endif /* CONFIG_OMAP_MUX */
index 93c7f4a..e27041f 100644 (file)
@@ -59,20 +59,12 @@ int ocpi_enable(void)
 
        /* Make sure there's clock for OCPI */
 
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+#if defined(CONFIG_ARCH_OMAP16XX)
         if (cpu_is_omap1610() || cpu_is_omap1710()) {
-               val = omap_readl(OMAP1610_ARM_IDLECT3);
+               val = omap_readl(OMAP16XX_ARM_IDLECT3);
                val |= EN_OCPI_CK;
                val &= ~IDLOCPI_ARM;
-               omap_writel(val, OMAP1610_ARM_IDLECT3);
-        }
-#endif
-#ifdef CONFIG_ARCH_OMAP5912
-        if (cpu_is_omap5912()) {
-               val = omap_readl(OMAP5912_ARM_IDLECT3);
-               val |= EN_OCPI_CK;
-               val &= ~IDLOCPI_ARM;
-               omap_writel(val, OMAP5912_ARM_IDLECT3);
+               omap_writel(val, OMAP16XX_ARM_IDLECT3);
         }
 #endif
        /* Enable access for OHCI in OCPI */
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 */
index cb3c5d6..f673eee 100644 (file)
@@ -1,8 +1,14 @@
 /*
- * arch/arm/mach-omap/time.c
+ * linux/arch/arm/mach-omap/time.c
  *
- * OMAP Timer Tick 
+ * OMAP Timers
  *
+ * Copyright (C) 2004 Nokia Corporation
+ * Partial timer rewrite and additional VST timer support by
+ * Tony Lindgen <tony@atomide.com> and
+ * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ * MPU timer code based on the older MPU timer code for OMAP
  * Copyright (C) 2000 RidgeRun, Inc.
  * Author: Greg Lonnon <glonnon@ridgerun.com>
  *
@@ -33,6 +39,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
-#include <asm/arch/clocks.h>
-
-#ifndef __instrument
-#define __instrument
-#define __noinstrument __attribute__ ((no_instrument_function))
-#endif
 
-typedef struct {
-       u32 cntl;     /* CNTL_TIMER, R/W */
-       u32 load_tim; /* LOAD_TIM,   W */
-       u32 read_tim; /* READ_TIM,   R */
-} mputimer_regs_t;
-
-#define mputimer_base(n) \
-    ((volatile mputimer_regs_t*)IO_ADDRESS(OMAP_MPUTIMER_BASE + \
-                                (n)*OMAP_MPUTIMER_OFFSET))
-
-static inline unsigned long timer32k_read(int reg) {
-       unsigned long val;
-       val = omap_readw(reg + OMAP_32kHz_TIMER_BASE);
-       return val;
-}
-static inline void timer32k_write(int reg,int val) {
-       omap_writew(val, reg + OMAP_32kHz_TIMER_BASE);
-}
+struct sys_timer omap_timer;
 
 /*
- * How long is the timer interval? 100 HZ, right...
- * IRQ rate = (TVR + 1) / 32768 seconds
- * TVR = 32768 * IRQ_RATE -1
- * IRQ_RATE =  1/100
- * TVR = 326
+ * ---------------------------------------------------------------------------
+ * MPU timer
+ * ---------------------------------------------------------------------------
  */
-#define TIMER32k_PERIOD 326
-//#define TIMER32k_PERIOD 0x7ff
+#define OMAP_MPU_TIMER1_BASE           (0xfffec500)
+#define OMAP_MPU_TIMER2_BASE           (0xfffec600)
+#define OMAP_MPU_TIMER3_BASE           (0xfffec700)
+#define OMAP_MPU_TIMER_BASE            OMAP_MPU_TIMER1_BASE
+#define OMAP_MPU_TIMER_OFFSET          0x100
 
-static inline void start_timer32k(void) {
-       timer32k_write(TIMER32k_CR,
-                      TIMER32k_TSS | TIMER32k_TRB |
-                      TIMER32k_INT | TIMER32k_ARL);
-}
+#define MPU_TIMER_FREE                 (1 << 6)
+#define MPU_TIMER_CLOCK_ENABLE         (1 << 5)
+#define MPU_TIMER_AR                   (1 << 1)
+#define MPU_TIMER_ST                   (1 << 0)
 
-#ifdef CONFIG_MACH_OMAP_PERSEUS2
 /*
- * After programming PTV with 0 and setting the MPUTIM_CLOCK_ENABLE
- * (external clock enable)  bit, the timer count rate is 6.5 MHz (13
- * MHZ input/2). !! The divider by 2 is undocumented !!
+ * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs
+ * will break. On P2, the timer count rate is 6.5 MHz after programming PTV
+ * with 0. This divides the 13MHz input by 2, and is undocumented.
  */
-#define MPUTICKS_PER_SEC (13000000/2)
-#else
-/*
- * After programming PTV with 0, the timer count rate is 6 MHz.
- * WARNING! this must be an even number, or machinecycles_to_usecs
- * below will break.
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+/* REVISIT: This ifdef construct should be replaced by a query to clock
+ * framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz.
  */
-#define MPUTICKS_PER_SEC  (12000000/2)
+#define MPU_TICKS_PER_SEC              (13000000 / 2)
+#else
+#define MPU_TICKS_PER_SEC              (12000000 / 2)
 #endif
 
-static int mputimer_started[3] = {0,0,0};
+#define MPU_TIMER_TICK_PERIOD          ((MPU_TICKS_PER_SEC / HZ) - 1)
 
-static inline void __noinstrument start_mputimer(int n,
-                                                unsigned long load_val)
-{
-       volatile mputimer_regs_t* timer = mputimer_base(n);
-
-       mputimer_started[n] = 0;
-       timer->cntl = MPUTIM_CLOCK_ENABLE;
-       udelay(1);
-
-       timer->load_tim = load_val;
-        udelay(1);
-       timer->cntl = (MPUTIM_CLOCK_ENABLE | MPUTIM_AR | MPUTIM_ST);
-       mputimer_started[n] = 1;
-}
+typedef struct {
+       u32 cntl;                       /* CNTL_TIMER, R/W */
+       u32 load_tim;                   /* LOAD_TIM,   W */
+       u32 read_tim;                   /* READ_TIM,   R */
+} omap_mpu_timer_regs_t;
 
-static inline unsigned long __noinstrument
-read_mputimer(int n)
-{
-       volatile mputimer_regs_t* timer = mputimer_base(n);
-       return (mputimer_started[n] ? timer->read_tim : 0);
-}
+#define omap_mpu_timer_base(n)                                         \
+((volatile omap_mpu_timer_regs_t*)IO_ADDRESS(OMAP_MPU_TIMER_BASE +     \
+                                (n)*OMAP_MPU_TIMER_OFFSET))
 
-void __noinstrument start_mputimer1(unsigned long load_val)
-{
-       start_mputimer(0, load_val);
-}
-void __noinstrument start_mputimer2(unsigned long load_val)
+static inline unsigned long omap_mpu_timer_read(int nr)
 {
-       start_mputimer(1, load_val);
-}
-void __noinstrument start_mputimer3(unsigned long load_val)
-{
-       start_mputimer(2, load_val);
+       volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+       return timer->read_tim;
 }
 
-unsigned long __noinstrument read_mputimer1(void)
-{
-       return read_mputimer(0);
-}
-unsigned long __noinstrument read_mputimer2(void)
-{
-       return read_mputimer(1);
-}
-unsigned long __noinstrument read_mputimer3(void)
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
 {
-       return read_mputimer(2);
-}
+       volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
 
-unsigned long __noinstrument do_getmachinecycles(void)
-{
-       return 0 - read_mputimer(0);
+       timer->cntl = MPU_TIMER_CLOCK_ENABLE;
+       udelay(1);
+       timer->load_tim = load_val;
+        udelay(1);
+       timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
 }
 
-unsigned long __noinstrument machinecycles_to_usecs(unsigned long mputicks)
+unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks)
 {
        /* Round up to nearest usec */
-       return ((mputicks * 1000) / (MPUTICKS_PER_SEC / 2 / 1000) + 1) >> 1;
+       return ((nr_ticks * 1000) / (MPU_TICKS_PER_SEC / 2 / 1000) + 1) >> 1;
 }
 
 /*
- * This marks the time of the last system timer interrupt
- * that was *processed by the ISR* (timer 2).
+ * Last processed system timer interrupt
  */
-static unsigned long systimer_mark;
+static unsigned long omap_mpu_timer_last = 0;
 
-static unsigned long omap_gettimeoffset(void)
+/*
+ * Returns elapsed usecs since last system timer interrupt
+ */
+static unsigned long omap_mpu_timer_gettimeoffset(void)
 {
-       /* Return elapsed usecs since last system timer ISR */
-       return machinecycles_to_usecs(do_getmachinecycles() - systimer_mark);
+       unsigned long now = 0 - omap_mpu_timer_read(0);
+       unsigned long elapsed = now - omap_mpu_timer_last;
+
+       return omap_mpu_timer_ticks_to_usecs(elapsed);
 }
 
-static irqreturn_t
-omap_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+/*
+ * Elapsed time between interrupts is calculated using timer0.
+ * Latency during the interrupt is calculated using timer1.
+ * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz).
+ */
+static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id,
+                                       struct pt_regs *regs)
 {
-       unsigned long now, ilatency;
-
-       /*
-        * Mark the time at which the timer interrupt ocurred using
-        * timer1. We need to remove interrupt latency, which we can
-        * retrieve from the current system timer2 counter. Both the
-        * offset timer1 and the system timer2 are counting at 6MHz,
-        * so we're ok.
-        */
-       now = 0 - read_mputimer1();
-       ilatency = MPUTICKS_PER_SEC / 100 - read_mputimer2();
-       systimer_mark = now - ilatency;
+       unsigned long now, latency;
 
+       write_seqlock(&xtime_lock);
+       now = 0 - omap_mpu_timer_read(0);
+       latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1);
+       omap_mpu_timer_last = now - latency;
        timer_tick(regs);
+       write_sequnlock(&xtime_lock);
 
        return IRQ_HANDLED;
 }
 
-static struct irqaction omap_timer_irq = {
-       .name           = "OMAP Timer Tick",
+static struct irqaction omap_mpu_timer_irq = {
+       .name           = "mpu timer",
        .flags          = SA_INTERRUPT,
-       .handler        = omap_timer_interrupt
+       .handler        = omap_mpu_timer_interrupt
 };
 
-void __init omap_init_time(void)
+static __init void omap_init_mpu_timer(void)
 {
-       /* Since we don't call request_irq, we must init the structure */
-       gettimeoffset = omap_gettimeoffset;
-
-#ifdef OMAP1510_USE_32KHZ_TIMER
-       timer32k_write(TIMER32k_CR, 0x0);
-       timer32k_write(TIMER32k_TVR,TIMER32k_PERIOD);
-       setup_irq(INT_OS_32kHz_TIMER, &omap_timer_irq);
-       start_timer32k();
-#else
-       setup_irq(INT_TIMER2, &omap_timer_irq);
-       start_mputimer2(MPUTICKS_PER_SEC / 100 - 1);
-#endif
+       omap_timer.offset = omap_mpu_timer_gettimeoffset;
+       setup_irq(INT_TIMER2, &omap_mpu_timer_irq);
+       omap_mpu_timer_start(0, 0xffffffff);
+       omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD);
 }
 
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+void __init omap_timer_init(void)
+{
+       omap_init_mpu_timer();
+}
+
+struct sys_timer omap_timer = {
+       .init           = omap_timer_init,
+       .offset         = NULL,         /* Initialized later */
+};
index f3451d2..4eeabe4 100644 (file)
  */
 
 /* TESTED ON:
- *  - 1611B H2 (with usb1 mini-AB)
- *  - 1510 Innovator with built-in transceiver (custom cable feeding 5V VBUS)
+ *  - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables
+ *  - 1510 Innovator UDC with bundled usb0 cable
+ *  - 1510 Innovator OHCI with bundled usb1/usb2 cable
+ *  - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS
  *  - 1710 custom development board using alternate pin group
  */
 
@@ -92,7 +94,10 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
        u32     syscon1 = 0;
 
        if (nwires == 0) {
-               USB_TRANSCEIVER_CTRL_REG &= ~(1 << 3);
+               if (!cpu_is_omap15xx()) {
+                       /* pulldown D+/D- */
+                       USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
+               }
                return 0;
        }
 
@@ -101,36 +106,30 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
         * USB0_VP and USB0_VM are always set on 1510, there's no muxing
         * available for them.
         */
-       if (nwires >= 2 && !cpu_is_omap1510()) {
+       if (nwires >= 2 && !cpu_is_omap15xx()) {
                omap_cfg_reg(AA9_USB0_VP);
                omap_cfg_reg(R9_USB0_VM);
        }
+       if (is_device)
+               omap_cfg_reg(W4_USB_PUEN);
 
        /* internal transceiver */
        if (nwires == 2) {
-               if (cpu_is_omap1510()) {
-                       /* This works for OHCI on 1510-Innovator, nothing to mux */
+               if (cpu_is_omap15xx()) {
+                       /* This works for OHCI on 1510-Innovator */
                        return 0;
                }
 
-#if 0
                /* NOTE:  host OR device mode for now, no OTG */
-               USB_TRANSCEIVER_CTRL_REG &= ~(3 << 4);
+               USB_TRANSCEIVER_CTRL_REG &= ~(7 << 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 */
@@ -170,7 +169,7 @@ static u32 __init omap_usb1_init(unsigned nwires)
 {
        u32     syscon1 = 0;
 
-       if (nwires != 6)
+       if (nwires != 6 && !cpu_is_omap15xx())
                USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R;
        if (nwires == 0)
                return 0;
@@ -178,11 +177,11 @@ static u32 __init omap_usb1_init(unsigned nwires)
        /* external transceiver */
        omap_cfg_reg(USB1_TXD);
        omap_cfg_reg(USB1_TXEN);
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                omap_cfg_reg(USB1_SEO);
                omap_cfg_reg(USB1_SPEED);
                // SUSP
-       } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) {
+       } else if (cpu_is_omap16xx()) {
                omap_cfg_reg(W13_1610_USB1_SE0);
                omap_cfg_reg(R13_1610_USB1_SPEED);
                // SUSP
@@ -203,7 +202,8 @@ static u32 __init omap_usb1_init(unsigned nwires)
                syscon1 = 3;
                omap_cfg_reg(USB1_VP);
                omap_cfg_reg(USB1_VM);
-               USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
+               if (!cpu_is_omap15xx())
+                       USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
                break;
        default:
                printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
@@ -216,31 +216,32 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
 {
        u32     syscon1 = 0;
 
-       if (alt_pingroup)
+       if (alt_pingroup || nwires == 0)
                return 0;
-       if (nwires != 6)
+       if (nwires != 6 && !cpu_is_omap15xx())
                USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
        if (nwires == 0)
                return 0;
 
        /* external transceiver */
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                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()) {
+               /* there is no USB2_SPEED */
+       } else if (cpu_is_omap16xx()) {
                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);
+               // FIXME omap_cfg_reg(USB2_SPEED);
        } else {
                pr_debug("usb unrecognized\n");
        }
        // omap_cfg_reg(USB2_SUSP);
-       // FIXME omap_cfg_reg(USB2_SPEED);
 
        switch (nwires) {
        case 3:
@@ -251,14 +252,14 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
                break;
        case 6:
                syscon1 = 3;
-               if (cpu_is_omap1510()) {
+               if (cpu_is_omap15xx()) {
                        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;
                }
-               USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
                break;
        default:
                printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
@@ -337,7 +338,7 @@ static struct platform_device ohci_device = {
        .dev = {
                .release                = usb_release,
                .dma_mask               = &ohci_dmamask,
-               .coherent_dma_mask      = 0x0fffffff,
+               .coherent_dma_mask      = 0xffffffff,
        },
        .num_resources  = ARRAY_SIZE(ohci_resources),
        .resource               = ohci_resources,
@@ -375,7 +376,11 @@ static struct platform_device otg_device = {
 
 // FIXME correct answer depends on hmc_mode,
 // as does any nonzero value for config->otg port number
+#ifdef CONFIG_USB_GADGET_OMAP
+#define        is_usb0_device(config)  1
+#else
 #define        is_usb0_device(config)  0
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -420,7 +425,7 @@ omap_otg_init(struct omap_usb_config *config)
        if (alt_pingroup)
                printk(", usb2 alt %d wires", config->pins[2]);
        else if (config->pins[0])
-               printk(", usb0 %d wires%s", config->pins[2],
+               printk(", usb0 %d wires%s", config->pins[0],
                        is_usb0_device(config) ? " (dev)" : "");
        if (config->pins[1])
                printk(", usb1 %d wires", config->pins[1]);
@@ -477,6 +482,19 @@ static inline void omap_otg_init(struct omap_usb_config *config) {}
 
 #ifdef CONFIG_ARCH_OMAP1510
 
+#define ULPD_SOFT_REQ_REG      __REG16(ULPD_SOFT_REQ)
+#define SOFT_UDC_REQ           (1 << 4)
+#define SOFT_DPLL_REQ          (1 << 0)
+
+#define ULPD_DPLL_CTRL_REG     __REG16(ULPD_DPLL_CTRL)
+#define DPLL_IOB               (1 << 13)
+#define DPLL_PLL_ENABLE                (1 << 4)
+#define DPLL_LOCK              (1 << 0)
+
+#define ULPD_APLL_CTRL_REG     __REG16(ULPD_APLL_CTRL)
+#define APLL_NDPLL_SWITCH      (1 << 0)
+
+
 static void __init omap_1510_usb_init(struct omap_usb_config *config)
 {
        int status;
@@ -490,16 +508,43 @@ static void __init omap_1510_usb_init(struct omap_usb_config *config)
        val |= (config->hmc_mode << 1);
        omap_writel(val, MOD_CONF_CTRL_0);
 
-       // FIXME this has a UDC controller too
+       printk("USB: hmc %d", config->hmc_mode);
+       if (config->pins[0])
+               printk(", usb0 %d wires%s", config->pins[0],
+                       is_usb0_device(config) ? " (dev)" : "");
+       if (config->pins[1])
+               printk(", usb1 %d wires", config->pins[1]);
+       if (config->pins[2])
+               printk(", usb2 %d wires", config->pins[2]);
+       printk("\n");
+
+       /* use DPLL for 48 MHz function clock */
+       pr_debug("APLL %04x DPLL %04x REQ %04x\n", ULPD_APLL_CTRL_REG,
+                       ULPD_DPLL_CTRL_REG, ULPD_SOFT_REQ_REG);
+       ULPD_APLL_CTRL_REG &= ~APLL_NDPLL_SWITCH;
+       ULPD_DPLL_CTRL_REG |= DPLL_IOB | DPLL_PLL_ENABLE;
+       ULPD_SOFT_REQ_REG |= SOFT_UDC_REQ | SOFT_DPLL_REQ;
+       while (!(ULPD_DPLL_CTRL_REG & DPLL_LOCK))
+               cpu_relax();
+
+#ifdef CONFIG_USB_GADGET_OMAP
+       if (config->register_dev) {
+               udc_device.dev.platform_data = config;
+               status = platform_device_register(&udc_device);
+               if (status)
+                       pr_debug("can't register UDC device, %d\n", status);
+               /* udc driver gates 48MHz by D+ pullup */
+       }
+#endif
 
 #if    defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-       if (config->otg || config->register_host) {
+       if (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);
+               /* hcd explicitly gates 48MHz */
        }
-       // FIXME completely untested ...
 #endif
 
 }
@@ -524,12 +569,9 @@ omap_usb_init(void)
        }
        platform_data = *config;
 
-       if (cpu_is_omap730()
-                       || cpu_is_omap1610()
-                       || cpu_is_omap1710()
-                       || cpu_is_omap5912())
+       if (cpu_is_omap730() || cpu_is_omap16xx())
                omap_otg_init(&platform_data);
-       else if (cpu_is_omap1510())
+       else if (cpu_is_omap15xx())
                omap_1510_usb_init(&platform_data);
        else {
                printk(KERN_ERR "USB: No init for your chip yet\n");
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
+
index 219fd4e..2c8d7c8 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/mainstone.h>
 #include <asm/arch/pxafb.h>
+#include <asm/arch/mmc.h>
 
 #include "generic.h"
 
@@ -170,6 +171,61 @@ static struct pxafb_mach_info toshiba_ltm035a776c __initdata = {
        .pxafb_backlight_power  = mainstone_backlight_power,
 };
 
+static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+       int err;
+
+       /*
+        * setup GPIO for PXA27x MMC controller
+        */
+       pxa_gpio_mode(GPIO32_MMCCLK_MD);
+       pxa_gpio_mode(GPIO112_MMCCMD_MD);
+       pxa_gpio_mode(GPIO92_MMCDAT0_MD);
+       pxa_gpio_mode(GPIO109_MMCDAT1_MD);
+       pxa_gpio_mode(GPIO110_MMCDAT2_MD);
+       pxa_gpio_mode(GPIO111_MMCDAT3_MD);
+
+       /* make sure SD/Memory Stick multiplexer's signals
+        * are routed to MMC controller
+        */
+       MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL;
+
+       err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, SA_INTERRUPT,
+                            "MMC card detect", data);
+       if (err) {
+               printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void mainstone_mci_setpower(struct device *dev, unsigned int vdd)
+{
+       struct pxamci_platform_data* p_d = dev->platform_data;
+
+       if (( 1 << vdd) & p_d->ocr_mask) {
+               printk(KERN_DEBUG "%s: on\n", __FUNCTION__);
+               MST_MSCWR1 |= MST_MSCWR1_MMC_ON;
+               MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL;
+       } else {
+               printk(KERN_DEBUG "%s: off\n", __FUNCTION__);
+               MST_MSCWR1 &= ~MST_MSCWR1_MMC_ON;
+       }
+}
+
+static void mainstone_mci_exit(struct device *dev, void *data)
+{
+       free_irq(MAINSTONE_MMC_IRQ, data);
+}
+
+static struct pxamci_platform_data mainstone_mci_platform_data = {
+       .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
+       .init           = mainstone_mci_init,
+       .setpower       = mainstone_mci_setpower,
+       .exit           = mainstone_mci_exit,
+};
+
 static void __init mainstone_init(void)
 {
        platform_device_register(&smc91x_device);
@@ -180,6 +236,8 @@ static void __init mainstone_init(void)
                set_pxa_fb_info(&toshiba_ltm04c380k);
        else
                set_pxa_fb_info(&toshiba_ltm035a776c);
+
+       pxa_set_mci_info(&mainstone_mci_platform_data);
 }
 
 
@@ -198,6 +256,6 @@ MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
        BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
        MAPIO(mainstone_map_io)
        INITIRQ(mainstone_init_irq)
-       INITTIME(pxa_init_time)
+       .timer          = &pxa_timer,
        INIT_MACHINE(mainstone_init)
 MACHINE_END
index e5e97fe..7e863af 100644 (file)
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <asm/arch/pxa-regs.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <linux/device.h>
 
 #include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/pxa-regs.h>
 
 #include "generic.h"
 
@@ -117,3 +119,45 @@ unsigned int get_lcdclk_frequency_10khz(void)
 EXPORT_SYMBOL(get_clk_frequency_khz);
 EXPORT_SYMBOL(get_memclk_frequency_10khz);
 EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
+
+
+/*
+ * device registration specific to PXA27x.
+ */
+
+static u64 pxa27x_dmamask = 0xffffffffUL;
+
+static struct resource pxa27x_ohci_resources[] = {
+       [0] = {
+               .start  = 0x4C000000,
+               .end    = 0x4C00ff6f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_USBH1,
+               .end    = IRQ_USBH1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device ohci_device = {
+       .name           = "pxa27x-ohci",
+       .id             = -1,
+       .dev            = {
+               .dma_mask = &pxa27x_dmamask,
+               .coherent_dma_mask = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(pxa27x_ohci_resources),
+       .resource       = pxa27x_ohci_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &ohci_device,
+};
+
+static int __init pxa27x_init(void)
+{
+       return platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+subsys_initcall(pxa27x_init);
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);
index a49fc02..473fb61 100644 (file)
@@ -75,6 +75,8 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        int next_match;
 
+       write_seqlock(&xtime_lock);
+
        /* Loop until we get ahead of the free running timer.
         * This ensures an exact clock tick count and time accuracy.
         * IRQs are disabled inside the loop to ensure coherence between
@@ -96,6 +98,8 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                next_match = (OSMR0 += LATCH);
        } while( (signed long)(next_match - OSCR) <= 8 );
 
+       write_sequnlock(&xtime_lock);
+
        return IRQ_HANDLED;
 }
 
@@ -105,11 +109,10 @@ static struct irqaction pxa_timer_irq = {
        .handler        = pxa_timer_interrupt
 };
 
-void __init pxa_init_time(void)
+static void __init pxa_timer_init(void)
 {
        struct timespec tv;
 
-       gettimeoffset = pxa_gettimeoffset;
        set_rtc = pxa_set_rtc;
 
        tv.tv_nsec = 0;
@@ -123,3 +126,39 @@ void __init pxa_init_time(void)
        OSCR = 0;               /* initialize free-running timer, force first match */
 }
 
+#ifdef CONFIG_PM
+static unsigned long osmr[4], oier;
+
+static void pxa_timer_suspend(void)
+{
+       osmr[0] = OSMR0;
+       osmr[1] = OSMR1;
+       osmr[2] = OSMR2;
+       osmr[3] = OSMR3;
+       oier = OIER;
+}
+
+static void pxa_timer_resume(void)
+{
+       OSMR0 = osmr[0];
+       OSMR1 = osmr[1];
+       OSMR2 = osmr[2];
+       OSMR3 = osmr[3];
+       OIER = oier;
+
+       /*
+        * OSMR0 is the system timer: make sure OSCR is sufficiently behind
+        */
+       OSCR = OSMR0 - LATCH;
+}
+#else
+#define pxa_timer_suspend NULL
+#define pxa_timer_resume NULL
+#endif
+
+struct sys_timer pxa_timer = {
+       .init           = pxa_timer_init,
+       .suspend        = pxa_timer_suspend,
+       .resume         = pxa_timer_resume,
+       .offset         = pxa_gettimeoffset,
+};
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
+
index a12ade7..107c12a 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/err.h>
+#include <linux/device.h>
 
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 
 #include "clock.h"
 
+/* clock information */
+
+unsigned long s3c24xx_xtal = 12*1000*1000;     /* default 12MHz */
+unsigned long s3c24xx_fclk;
+unsigned long s3c24xx_hclk;
+unsigned long s3c24xx_pclk;
 
 static LIST_HEAD(clocks);
 static DECLARE_MUTEX(clocks_sem);
@@ -53,7 +60,7 @@ static DECLARE_MUTEX(clocks_sem);
 
 /* old functions */
 
-void s3c2410_clk_enable(unsigned int clocks, unsigned int enable)
+void inline s3c2410_clk_enable(unsigned int clocks, unsigned int enable)
 {
        unsigned long clkcon;
        unsigned long flags;
@@ -66,11 +73,26 @@ void s3c2410_clk_enable(unsigned int clocks, unsigned int enable)
        if (enable)
                clkcon |= clocks;
 
+       /* ensure none of the special function bits set */
+       clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
+
        __raw_writel(clkcon, S3C2410_CLKCON);
 
        local_irq_restore(flags);
 }
 
+/* enable and disable calls for use with the clk struct */
+
+static int clk_null_enable(struct clk *clk, int enable)
+{
+       return 0;
+}
+
+int s3c2410_clkcon_enable(struct clk *clk, int enable)
+{
+       s3c2410_clk_enable(clk->ctrlbit, enable);
+       return 0;
+}
 
 /* Clock API calls */
 
@@ -78,17 +100,35 @@ struct clk *clk_get(struct device *dev, const char *id)
 {
        struct clk *p;
        struct clk *clk = ERR_PTR(-ENOENT);
+       int idno;
+
+       idno = (dev == NULL) ? -1 : to_platform_device(dev)->id;
 
        down(&clocks_sem);
+
        list_for_each_entry(p, &clocks, list) {
-               if (strcmp(id, p->name) == 0 &&
+               if (p->id == idno &&
+                   strcmp(id, p->name) == 0 &&
                    try_module_get(p->owner)) {
                        clk = p;
                        break;
                }
        }
-       up(&clocks_sem);
 
+       /* check for the case where a device was supplied, but the
+        * clock that was being searched for is not device specific */
+
+       if (IS_ERR(clk)) {
+               list_for_each_entry(p, &clocks, list) {
+                       if (p->id == -1 && strcmp(id, p->name) == 0 &&
+                           try_module_get(p->owner)) {
+                               clk = p;
+                               break;
+                       }
+               }
+       }
+
+       up(&clocks_sem);
        return clk;
 }
 
@@ -99,15 +139,16 @@ void clk_put(struct clk *clk)
 
 int clk_enable(struct clk *clk)
 {
-       if (clk->ctrlbit != 0)
-               s3c2410_clk_enable(clk->ctrlbit, 1);
+       if (IS_ERR(clk))
+               return -EINVAL;
 
-       return 0;
+       return (clk->enable)(clk, 1);
 }
 
 void clk_disable(struct clk *clk)
 {
-       s3c2410_clk_enable(clk->ctrlbit, 0);
+       if (!IS_ERR(clk))
+               (clk->enable)(clk, 0);
 }
 
 
@@ -125,8 +166,14 @@ void clk_unuse(struct clk *clk)
 
 unsigned long clk_get_rate(struct clk *clk)
 {
-       if (clk->parent != NULL)
-               return clk->parent->rate;
+       if (IS_ERR(clk))
+               return 0;
+
+       if (clk->rate != 0)
+               return clk->rate;
+
+       while (clk->parent != NULL && clk->rate == 0)
+               clk = clk->parent;
 
        return clk->rate;
 }
@@ -160,90 +207,151 @@ EXPORT_SYMBOL(clk_get_parent);
 /* base clocks */
 
 static struct clk clk_f = {
-       .name          = "fclk",
-       .rate          = 0,
-       .parent        = NULL,
-       .ctrlbit       = 0
+       .name           = "fclk",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = NULL,
+       .ctrlbit        = 0,
 };
 
 static struct clk clk_h = {
-       .name          = "hclk",
-       .rate          = 0,
-       .parent        = NULL,
-       .ctrlbit       = 0
+       .name           = "hclk",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = NULL,
+       .ctrlbit        = 0,
 };
 
 static struct clk clk_p = {
-       .name          = "pclk",
-       .rate          = 0,
-       .parent        = NULL,
-       .ctrlbit       = 0
+       .name           = "pclk",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = NULL,
+       .ctrlbit        = 0,
 };
 
+/* clocks that could be registered by external code */
+
+struct clk s3c24xx_dclk0 = {
+       .name           = "dclk0",
+       .id             = -1,
+};
+
+struct clk s3c24xx_dclk1 = {
+       .name           = "dclk1",
+       .id             = -1,
+};
+
+struct clk s3c24xx_clkout0 = {
+       .name           = "clkout0",
+       .id             = -1,
+};
+
+struct clk s3c24xx_clkout1 = {
+       .name           = "clkout1",
+       .id             = -1,
+};
+
+struct clk s3c24xx_uclk = {
+       .name           = "uclk",
+       .id             = -1,
+};
+
+
 /* clock definitions */
 
 static struct clk init_clocks[] = {
        { .name    = "nand",
+         .id      = -1,
          .parent  = &clk_h,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_NAND
        },
        { .name    = "lcd",
+         .id      = -1,
          .parent  = &clk_h,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_LCDC
        },
        { .name    = "usb-host",
+         .id      = -1,
          .parent  = &clk_h,
-         .ctrlbit =   S3C2410_CLKCON_USBH
+         .enable  = s3c2410_clkcon_enable,
+         .ctrlbit = S3C2410_CLKCON_USBH
        },
        { .name    = "usb-device",
+         .id      = -1,
          .parent  = &clk_h,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_USBD
        },
        { .name    = "timers",
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_PWMT
        },
        { .name    = "sdi",
+         .id      = -1,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_SDI
        },
-       { .name    = "uart0",
+       { .name    = "uart",
+         .id      = 0,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_UART0
        },
-       { .name    = "uart1",
+       { .name    = "uart",
+         .id      = 1,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_UART1
        },
-       { .name    = "uart2",
+       { .name    = "uart",
+         .id      = 2,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_UART2
        },
        { .name    = "gpio",
+         .id      = -1,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_GPIO
        },
        { .name    = "rtc",
+         .id      = -1,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_RTC
        },
        { .name    = "adc",
+         .id      = -1,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_ADC
        },
        { .name    = "i2c",
+         .id      = -1,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_IIC
        },
        { .name    = "iis",
+         .id      = -1,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_IIS
        },
        { .name    = "spi",
+         .id      = -1,
          .parent  = &clk_p,
+         .enable  = s3c2410_clkcon_enable,
          .ctrlbit = S3C2410_CLKCON_SPI
        },
        { .name    = "watchdog",
+         .id      = -1,
          .parent  = &clk_p,
          .ctrlbit = 0
        }
@@ -256,6 +364,9 @@ int s3c2410_register_clock(struct clk *clk)
        clk->owner = THIS_MODULE;
        atomic_set(&clk->used, 0);
 
+       if (clk->enable == NULL)
+               clk->enable = clk_null_enable;
+
        /* add to the list of available clocks */
 
        down(&clocks_sem);
@@ -267,7 +378,7 @@ int s3c2410_register_clock(struct clk *clk)
 
 /* initalise all the clocks */
 
-static int __init s3c2410_init_clocks(void)
+int __init s3c2410_init_clocks(void)
 {
        struct clk *clkp = init_clocks;
        int ptr;
@@ -277,12 +388,29 @@ static int __init s3c2410_init_clocks(void)
 
        /* 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);
+       clk_h.rate = s3c24xx_hclk;
+       clk_p.rate = s3c24xx_pclk;
+       clk_f.rate = s3c24xx_fclk;
+
+       /* it looks like just setting the register here is not good
+        * enough, and causes the odd hang at initial boot time, so
+        * do all of them indivdually.
+        *
+        * I think disabling the LCD clock if the LCD is active is
+        * very dangerous, and therefore the bootloader should be
+        * careful to not enable the LCD clock if it is not needed.
+        *
+        * and of course, this looks neater
+        */
+
+       s3c2410_clk_enable(S3C2410_CLKCON_NAND, 0);
+       s3c2410_clk_enable(S3C2410_CLKCON_USBH, 0);
+       s3c2410_clk_enable(S3C2410_CLKCON_USBD, 0);
+       s3c2410_clk_enable(S3C2410_CLKCON_ADC, 0);
+       s3c2410_clk_enable(S3C2410_CLKCON_IIC, 0);
+       s3c2410_clk_enable(S3C2410_CLKCON_SPI, 0);
+
+       /* assume uart clocks are correctly setup */
 
        /* register our clocks */
 
@@ -306,5 +434,4 @@ static int __init s3c2410_init_clocks(void)
        return 0;
 }
 
-arch_initcall(s3c2410_init_clocks);
 
index 4c7b94e..f66d901 100644 (file)
@@ -2,7 +2,7 @@
  * linux/arch/arm/mach-s3c2410/clock.h
  *
  * Copyright (c) 2004 Simtec Electronics
- * Written by Ben Dooks, <ben@simtec.co.uk>
+ *     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
@@ -14,7 +14,34 @@ struct clk {
        struct module        *owner;
        struct clk           *parent;
        const char           *name;
+       int                   id;
        atomic_t              used;
        unsigned long         rate;
        unsigned long         ctrlbit;
+       int                 (*enable)(struct clk *, int enable);
 };
+
+/* other clocks which may be registered by board support */
+
+extern struct clk s3c24xx_dclk0;
+extern struct clk s3c24xx_dclk1;
+extern struct clk s3c24xx_clkout0;
+extern struct clk s3c24xx_clkout1;
+extern struct clk s3c24xx_uclk;
+
+/* processor clock settings, in Hz */
+
+extern unsigned long s3c24xx_xtal;
+extern unsigned long s3c24xx_pclk;
+extern unsigned long s3c24xx_hclk;
+extern unsigned long s3c24xx_fclk;
+
+/* exports for arch/arm/mach-s3c2410
+ *
+ * Please DO NOT use these outside of arch/arm/mach-s3c2410
+*/
+
+extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
+extern int s3c2410_register_clock(struct clk *clk);
+extern int s3c2410_init_clocks(void);
+
index 42eec79..f557017 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/arch/regs-gpio.h>
 
 #include "cpu.h"
+#include "clock.h"
 #include "s3c2410.h"
 #include "s3c2440.h"
 
@@ -65,7 +66,7 @@ static struct cpu_table cpu_ids[] __initdata = {
                .name   = name_s3c2410
        },
        {
-               .idcode = 0x3241002,
+               .idcode = 0x32410002,
                .idmask = 0xffffffff,
                .map_io = s3c2410_map_io,
                .init   = s3c2410_init,
@@ -104,7 +105,7 @@ s3c_lookup_cpu(unsigned long idcode)
        int count;
 
        tab = cpu_ids;
-       for (count = 0; count < ARRAY_SIZE(cpu_ids); count++) {
+       for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) {
                if ((idcode & tab->idmask) == tab->idcode)
                        return tab;
        }
@@ -112,6 +113,26 @@ s3c_lookup_cpu(unsigned long idcode)
        return NULL;
 }
 
+/* board information */
+
+static struct s3c24xx_board *board;
+
+void s3c24xx_set_board(struct s3c24xx_board *b)
+{
+       int i;
+
+       board = b;
+
+       if (b->clocks_count != 0) {
+               struct clk **ptr = b->clocks;;
+
+               for (i = b->clocks_count; i > 0; i--, ptr++)
+                       s3c2410_register_clock(*ptr);
+       }
+}
+
+/* cpu information */
+
 static struct cpu_table *cpu;
 
 void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
@@ -141,12 +162,35 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
 
 static int __init s3c_arch_init(void)
 {
+       int ret;
+
        // do the correct init for cpu
 
        if (cpu == NULL)
                panic("s3c_arch_init: NULL cpu\n");
 
-       return (cpu->init)();
+       ret = (cpu->init)();
+       if (ret != 0)
+               return ret;
+
+       if (board != NULL) {
+               struct platform_device **ptr = board->devices;
+               int i;
+
+               for (i = 0; i < board->devices_count; i++, ptr++) {
+                       ret = platform_device_register(*ptr);
+
+                       if (ret) {
+                               printk(KERN_ERR "s3c24xx: failed to add board device %s (%d) @%p\n", (*ptr)->name, ret, *ptr);
+                       }
+               }
+
+               /* mask any error, we may not need all these board
+                * devices */
+               ret = 0;
+       }
+
+       return ret;
 }
 
 arch_initcall(s3c_arch_init);
index b0053d7..e0996d5 100644 (file)
@@ -11,6 +11,7 @@
  *
  * Modifications:
  *     24-Aug-2004 BJD  Start of generic S3C24XX support
+ *     18-Oct-2004 BJD  Moved board struct into this file
 */
 
 #define IODESC_ENT(x) { S3C2410_VA_##x, S3C2410_PA_##x, S3C2410_SZ_##x, MT_DEVICE }
@@ -39,3 +40,20 @@ extern void s3c2440_map_io(struct map_desc *mach_desc, int size);
 
 extern void s3c24xx_init_io(struct map_desc *mach_desc, int size);
 
+/* the board structure is used at first initialsation time
+ * to get info such as the devices to register for this
+ * board. This is done because platfrom_add_devices() cannot
+ * be called from the map_io entry.
+*/
+
+struct s3c24xx_board {
+       struct platform_device  **devices;
+       unsigned int              devices_count;
+
+       struct clk              **clocks;
+       unsigned int              clocks_count;
+};
+
+extern void s3c24xx_set_board(struct s3c24xx_board *board);
+
+
index 7cf560c..b1826df 100644 (file)
 #include <asm/io.h>
 #include <asm/irq.h>
 
+#include <asm/arch/regs-serial.h>
+
 #include "devs.h"
 
+/* Serial port registrations */
+
+struct platform_device *s3c24xx_uart_devs[3];
+
 /* USB Host Controller */
 
 static struct resource s3c_usb_resource[] = {
index 819e5af..a382023 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-bast/dma.c
  *
  * (c) 2003,2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ *     Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 DMA core
  *
@@ -12,6 +12,9 @@
  * published by the Free Software Foundation.
  *
  * Changelog:
+ *  18-Nov-2004 BJD  Removed error for loading onto stopped channel
+ *  10-Nov-2004 BJD  Ensure all external symbols exported for modules
+ *  10-Nov-2004 BJD  Use sys_device and sysdev_class for power management
  *  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
@@ -38,6 +41,7 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/sysdev.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
@@ -52,7 +56,7 @@
 #include <asm/arch/map.h>
 
 /* io map for dma */
-static void *dma_base;
+static void __iomem *dma_base;
 
 /* dma channel state information */
 s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS];
@@ -490,10 +494,6 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id,
        } 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;
                }
        }
 
@@ -501,6 +501,8 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id,
        return 0;
 }
 
+EXPORT_SYMBOL(s3c2410_dma_enqueue);
+
 static inline void
 s3c2410_dma_freebuf(s3c2410_dma_buf_t *buf)
 {
@@ -648,6 +650,9 @@ s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
 
                        break;
 
+               case S3C2410_DMALOAD_1LOADED_1RUNNING:
+                       goto no_load;
+
                default:
                        printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
                               chan->number, chan->load_state);
@@ -668,6 +673,7 @@ s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
                }
        }
 
+ no_load:
        return IRQ_HANDLED;
 }
 
@@ -736,6 +742,8 @@ int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,
        return 0;
 }
 
+EXPORT_SYMBOL(s3c2410_dma_request);
+
 /* s3c2410_dma_free
  *
  * release the given channel back to the system, will stop and flush
@@ -780,6 +788,8 @@ int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client)
        return 0;
 }
 
+EXPORT_SYMBOL(s3c2410_dma_free);
+
 static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)
 {
        unsigned long tmp;
@@ -886,6 +896,7 @@ s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op)
        return -ENOENT;      /* unknown, don't bother */
 }
 
+EXPORT_SYMBOL(s3c2410_dma_ctrl);
 
 /* DMA configuration for each channel
  *
@@ -941,6 +952,7 @@ int s3c2410_dma_config(dmach_t channel,
        return 0;
 }
 
+EXPORT_SYMBOL(s3c2410_dma_config);
 
 int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
 {
@@ -955,6 +967,9 @@ int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
        return 0;
 }
 
+EXPORT_SYMBOL(s3c2410_dma_setflags);
+
+
 /* do we need to protect the settings of the fields from
  * irq?
 */
@@ -972,6 +987,8 @@ int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
        return 0;
 }
 
+EXPORT_SYMBOL(s3c2410_dma_set_opfn);
+
 int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
 {
        s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
@@ -985,6 +1002,8 @@ int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
        return 0;
 }
 
+EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
+
 /* s3c2410_dma_devconfig
  *
  * configure the dma source/destination hardware type and address
@@ -1042,12 +1061,57 @@ int s3c2410_dma_devconfig(int channel,
        return -EINVAL;
 }
 
+EXPORT_SYMBOL(s3c2410_dma_devconfig);
+
+/* system device class */
+
+#ifdef CONFIG_PM
+
+static int s3c2410_dma_suspend(struct sys_device *dev, u32 state)
+{
+       s3c2410_dma_chan_t *cp = container_of(dev, s3c2410_dma_chan_t, dev);
+
+       printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
+
+       if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
+               /* the dma channel is still working, which is probably
+                * a bad thing to do over suspend/resume. We stop the
+                * channel and assume that the client is either going to
+                * retry after resume, or that it is broken.
+                */
+
+               printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
+                      cp->number);
+
+               s3c2410_dma_dostop(cp);
+       }
+
+       return 0;
+}
+
+static int s3c2410_dma_resume(struct sys_device *dev)
+{
+       return 0;
+}
+
+#else
+#define s3c2410_dma_suspend NULL
+#define s3c2410_dma_resume  NULL
+#endif /* CONFIG_PM */
+
+static struct sysdev_class dma_sysclass = {
+       set_kset_name("s3c24xx-dma"),
+       .suspend        = s3c2410_dma_suspend,
+       .resume         = s3c2410_dma_resume,
+};
+
 /* initialisation code */
 
 static int __init s3c2410_init_dma(void)
 {
-       int channel;
        s3c2410_dma_chan_t *cp;
+       int channel;
+       int ret;
 
        printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n");
 
@@ -1057,6 +1121,12 @@ static int __init s3c2410_init_dma(void)
                return -ENOMEM;
        }
 
+       ret = sysdev_class_register(&dma_sysclass);
+       if (ret != 0) {
+               printk(KERN_ERR "dma sysclass registration failed\n");
+               goto err;
+       }
+
        for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
                cp = &s3c2410_chans[channel];
 
@@ -1065,7 +1135,7 @@ static int __init s3c2410_init_dma(void)
                /* dma channel irqs are in order.. */
                cp->number = channel;
                cp->irq    = channel + IRQ_DMA0;
-               cp->regs   = (unsigned long)dma_base + (channel*0x40);
+               cp->regs   = dma_base + (channel*0x40);
 
                /* point current stats somewhere */
                cp->stats  = &cp->stats_store;
@@ -1075,11 +1145,22 @@ static int __init s3c2410_init_dma(void)
 
                cp->load_timeout = 1<<18;
 
-               printk("DMA channel %d at %08lx, irq %d\n",
+               /* register system device */
+
+               cp->dev.cls = &dma_sysclass;
+               cp->dev.id  = channel;
+               ret = sysdev_register(&cp->dev);
+
+               printk("DMA channel %d at %p, irq %d\n",
                       cp->number, cp->regs, cp->irq);
        }
 
        return 0;
+
+ err:
+       iounmap(dma_base);
+       dma_base = NULL;
+       return ret;
 }
 
 __initcall(s3c2410_init_dma);
index 8996725..129f29d 100644 (file)
@@ -28,6 +28,7 @@
  *     01-Oct-2004  BJD  Fixed mask bug in pullup() call
  *     01-Oct-2004  BJD  Added getirq() to turn pin into irqno
  *     04-Oct-2004  BJD  Added irq filter controls for GPIO
+ *     05-Nov-2004  BJD  EXPORT_SYMBOL() added for all code
  */
 
 
@@ -66,6 +67,8 @@ void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
        local_irq_restore(flags);
 }
 
+EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
+
 unsigned int s3c2410_gpio_getcfg(unsigned int pin)
 {
        unsigned long base = S3C2410_GPIO_BASE(pin);
@@ -80,6 +83,8 @@ unsigned int s3c2410_gpio_getcfg(unsigned int pin)
        return __raw_readl(base) & mask;
 }
 
+EXPORT_SYMBOL(s3c2410_gpio_getcfg);
+
 void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
 {
        unsigned long base = S3C2410_GPIO_BASE(pin);
@@ -100,6 +105,8 @@ void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
        local_irq_restore(flags);
 }
 
+EXPORT_SYMBOL(s3c2410_gpio_pullup);
+
 void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
 {
        unsigned long base = S3C2410_GPIO_BASE(pin);
@@ -117,6 +124,8 @@ void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
        local_irq_restore(flags);
 }
 
+EXPORT_SYMBOL(s3c2410_gpio_setpin);
+
 unsigned int s3c2410_gpio_getpin(unsigned int pin)
 {
        unsigned long base = S3C2410_GPIO_BASE(pin);
@@ -125,6 +134,8 @@ unsigned int s3c2410_gpio_getpin(unsigned int pin)
        return __raw_readl(base + 0x04) & (1<< offs);
 }
 
+EXPORT_SYMBOL(s3c2410_gpio_getpin);
+
 unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
 {
        unsigned long flags;
@@ -140,6 +151,8 @@ unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
        return misccr;
 }
 
+EXPORT_SYMBOL(s3c2410_modify_misccr);
+
 int s3c2410_gpio_getirq(unsigned int pin)
 {
        if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23)
@@ -157,6 +170,8 @@ int s3c2410_gpio_getirq(unsigned int pin)
        return (pin - S3C2410_GPG0) + IRQ_EINT8;
 }
 
+EXPORT_SYMBOL(s3c2410_gpio_getirq);
+
 int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
                           unsigned int config)
 {
@@ -192,3 +207,5 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
 
        return 0;
 }
+
+EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
index 1951a03..a8a48f7 100644 (file)
  *
  *   05-Oct-2004  Ben Dooks <ben@simtec.co.uk>
  *               Tidy up KF's patch and sort out new release
+ *
+ *   05-Oct-2004  Ben Dooks <ben@simtec.co.uk>
+ *               Add support for power management controls
+ *
+ *   04-Nov-2004  Ben Dooks
+ *               Fix standard IRQ wake for EINT0..4 and RTC
 */
 
-
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <asm/arch/regs-irq.h>
 #include <asm/arch/regs-gpio.h>
 
+#include "pm.h"
 
 #define irqdbf(x...)
 #define irqdbf2(x...)
 
+#define EXTINT_OFF (IRQ_EINT4 - 4)
+
+/* wakeup irq control */
+
+#ifdef CONFIG_PM
+
+/* state for IRQs over sleep */
+
+/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
+ *
+ * set bit to 1 in allow bitfield to enable the wakeup settings on it
+*/
+
+unsigned long s3c_irqwake_intallow     = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
+unsigned long s3c_irqwake_intmask      = 0xffffffffL;
+unsigned long s3c_irqwake_eintallow    = 0x0000fff0L;
+unsigned long s3c_irqwake_eintmask     = 0xffffffffL;
+
+static int
+s3c_irq_wake(unsigned int irqno, unsigned int state)
+{
+       unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
+
+       if (!(s3c_irqwake_intallow & irqbit))
+               return -ENOENT;
+
+       printk(KERN_INFO "wake %s for irq %d\n",
+              state ? "enabled" : "disabled", irqno);
+
+       if (!state)
+               s3c_irqwake_intmask |= irqbit;
+       else
+               s3c_irqwake_intmask &= ~irqbit;
+
+       return 0;
+}
+
+static int
+s3c_irqext_wake(unsigned int irqno, unsigned int state)
+{
+       unsigned long bit = 1L << (irqno - EXTINT_OFF);
+
+       if (!(s3c_irqwake_eintallow & bit))
+               return -ENOENT;
+
+       printk(KERN_INFO "wake %s for irq %d\n",
+              state ? "enabled" : "disabled", irqno);
+
+       if (!state)
+               s3c_irqwake_eintmask |= bit;
+       else
+               s3c_irqwake_eintmask &= ~bit;
+
+       return 0;
+}
+
+#else
+#define s3c_irqext_wake NULL
+#define s3c_irq_wake NULL
+#endif
+
+
 static void
 s3c_irq_mask(unsigned int irqno)
 {
@@ -109,21 +177,21 @@ s3c_irq_unmask(unsigned int irqno)
 static struct irqchip s3c_irq_level_chip = {
        .ack       = s3c_irq_maskack,
        .mask      = s3c_irq_mask,
-       .unmask    = s3c_irq_unmask
+       .unmask    = s3c_irq_unmask,
+       .wake      = s3c_irq_wake
 };
 
 static struct irqchip s3c_irq_chip = {
        .ack       = s3c_irq_ack,
        .mask      = s3c_irq_mask,
-       .unmask    = s3c_irq_unmask
+       .unmask    = s3c_irq_unmask,
+       .wake      = s3c_irq_wake
 };
 
 /* S3C2410_EINTMASK
  * S3C2410_EINTPEND
  */
 
-#define EXTINT_OFF (IRQ_EINT4 - 4)
-
 static void
 s3c_irqext_mask(unsigned int irqno)
 {
@@ -276,14 +344,16 @@ static struct irqchip s3c_irqext_chip = {
        .mask       = s3c_irqext_mask,
        .unmask     = s3c_irqext_unmask,
        .ack        = s3c_irqext_ack,
-       .type       = s3c_irqext_type
+       .type       = s3c_irqext_type,
+       .wake       = s3c_irqext_wake
 };
 
 static struct irqchip s3c_irq_eint0t4 = {
        .ack       = s3c_irq_ack,
        .mask      = s3c_irq_mask,
        .unmask    = s3c_irq_unmask,
-       .type      = s3c_irqext_type
+       .wake      = s3c_irq_wake,
+       .type      = s3c_irqext_type,
 };
 
 /* mask values for the parent registers for each of the interrupt types */
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
index 9f42865..61c3879 100644 (file)
@@ -58,14 +58,10 @@ static struct map_desc smdk2410_iodesc[] __initdata = {
 #define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
 #define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
 
-/* base baud rate for all our UARTs */
-static unsigned long smdk2410_serial_clock = 24*1000*1000;
-
 static struct s3c2410_uartcfg smdk2410_uartcfgs[] = {
        [0] = {
                .hwport      = 0,
                .flags       = 0,
-               .clock       = &smdk2410_serial_clock,
                .ucon        = UCON,
                .ulcon       = ULCON,
                .ufcon       = UFCON,
@@ -73,7 +69,6 @@ static struct s3c2410_uartcfg smdk2410_uartcfgs[] = {
        [1] = {
                .hwport      = 1,
                .flags       = 0,
-               .clock       = &smdk2410_serial_clock,
                .ucon        = UCON,
                .ulcon       = ULCON,
                .ufcon       = UFCON,
@@ -81,7 +76,6 @@ static struct s3c2410_uartcfg smdk2410_uartcfgs[] = {
        [2] = {
                .hwport      = 2,
                .flags       = 0,
-               .clock       = &smdk2410_serial_clock,
                .ucon        = UCON,
                .ulcon       = ULCON,
                .ufcon       = UFCON,
@@ -96,7 +90,7 @@ static struct platform_device *smdk2410_devices[] __initdata = {
        &s3c_device_iis,
 };
 
-static struct s3c2410_board smdk2410_board __initdata = {
+static struct s3c24xx_board smdk2410_board __initdata = {
        .devices       = smdk2410_devices,
        .devices_count = ARRAY_SIZE(smdk2410_devices)
 };
@@ -105,7 +99,7 @@ void __init smdk2410_map_io(void)
 {
        s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
        s3c2410_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
-       s3c2410_set_board(&smdk2410_board);
+       s3c24xx_set_board(&smdk2410_board);
 }
 
 void __init smdk2410_init_irq(void)
@@ -113,11 +107,6 @@ void __init smdk2410_init_irq(void)
        s3c2410_init_irq();
 }
 
-void __init smdk2410_init_time(void)
-{
-       s3c2410_init_time();
-}
-
 MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
                                    * to SMDK2410 */
      MAINTAINER("Jonas Dietsche")
@@ -125,7 +114,7 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc
      BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
      MAPIO(smdk2410_map_io)
      INITIRQ(smdk2410_init_irq)
-     INITTIME(smdk2410_init_time)
+     .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);
index fb30783..bc11fbf 100644 (file)
  *
  * Modifications:
  *     29-Aug-2004 BJD  Start of drive-strength control
+ *     09-Nov-2004 BJD  Added symbol export
 */
 
 #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 <linux/module.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -55,3 +54,5 @@ int s3c2440_set_dsc(unsigned int pin, unsigned int value)
        local_irq_restore(flags);
        return 0;
 }
+
+EXPORT_SYMBOL(s3c2440_set_dsc);
index f4bb10c..7e50eb9 100644 (file)
  * published by the Free Software Foundation.
  *
  * Modifications:
- *     24-Aug-2004 BJD  Start of s3c2440 support
+ *     24-Aug-2004 BJD  Start of s3c2440 support
+ *     12-Oct-2004 BJD  Moved clock info out to clock.c
+ *     01-Nov-2004 BJD  Fixed clock build code
+ *     09-Nov-2004 BJD  Added sysdev for power management
+ *     04-Nov-2004 BJD  New serial registration
+ *     15-Nov-2004 BJD  Rename the i2c device for the s3c2440
 */
 
 #include <linux/kernel.h>
@@ -20,6 +25,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/sysdev.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/hardware/clock.h>
 
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-gpioj.h>
+#include <asm/arch/regs-dsc.h>
 
 #include "s3c2440.h"
+#include "clock.h"
+#include "devs.h"
 #include "cpu.h"
+#include "pm.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),
@@ -124,9 +131,79 @@ static struct platform_device *uart_devices[] __initdata = {
        &s3c_uart2
 };
 
+/* uart initialisation */
+
+static int __initdata s3c2440_uart_count;
+
+void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       struct platform_device *platdev;
+       int uart;
+
+       for (uart = 0; uart < no; uart++, cfg++) {
+               platdev = uart_devices[cfg->hwport];
+
+               s3c24xx_uart_devs[uart] = platdev;
+               platdev->dev.platform_data = cfg;
+       }
+
+       s3c2440_uart_count = uart;
+}
+
+/* s3c2440 specific clock sources */
+
+static struct clk s3c2440_clk_cam = {
+       .name           = "camera",
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2440_CLKCON_CAMERA
+};
+
+static struct clk s3c2440_clk_ac97 = {
+       .name           = "ac97",
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2440_CLKCON_CAMERA
+};
+
+#ifdef CONFIG_PM
+
+struct sleep_save s3c2440_sleep[] = {
+       SAVE_ITEM(S3C2440_DSC0),
+       SAVE_ITEM(S3C2440_DSC1),
+       SAVE_ITEM(S3C2440_GPJDAT),
+       SAVE_ITEM(S3C2440_GPJCON),
+       SAVE_ITEM(S3C2440_GPJUP)
+};
+
+static int s3c2440_suspend(struct sys_device *dev, u32 state)
+{
+       s3c2410_pm_do_save(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
+       return 0;
+}
+
+static int s3c2440_resume(struct sys_device *dev)
+{
+       s3c2410_pm_do_restore(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
+       return 0;
+}
+
+#else
+#define s3c2440_suspend NULL
+#define s3c2440_resume  NULL
+#endif
+
+static struct sysdev_class s3c2440_sysclass = {
+       set_kset_name("s3c2440-core"),
+       .suspend        = s3c2440_suspend,
+       .resume         = s3c2440_resume
+};
+
+static struct sys_device s3c2440_sysdev = {
+       .cls            = &s3c2440_sysclass,
+};
+
 void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
 {
-       unsigned long tmp;
+       unsigned long clkdiv;
        unsigned long camdiv;
 
        /* register our io-tables */
@@ -137,15 +214,15 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int 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);
+       s3c24xx_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON),
+                                      s3c24xx_xtal) * 2;
 
-       tmp = __raw_readl(S3C2410_CLKDIVN);
+       clkdiv = __raw_readl(S3C2410_CLKDIVN);
        camdiv = __raw_readl(S3C2440_CAMDIVN);
 
        /* work out clock scalings */
 
-       switch (tmp & S3C2440_CLKDIVN_HDIVN_MASK) {
+       switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
        case S3C2440_CLKDIVN_HDIVN_1:
                s3c2440_hdiv = 1;
                break;
@@ -159,21 +236,40 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
                break;
 
        case S3C2440_CLKDIVN_HDIVN_3_6:
-               s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 6 : 3;
+               s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
                break;
        }
 
-       s3c2440_hclk = s3c2440_fclk / s3c2440_hdiv;
-       s3c2440_pclk = s3c2440_hclk / ((tmp & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
+       s3c24xx_hclk = s3c24xx_fclk / s3c2440_hdiv;
+       s3c24xx_pclk = s3c24xx_hclk / ((clkdiv & 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));
-}
+              print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk),
+              print_mhz(s3c24xx_pclk));
+
+       /* initialise the clocks here, to allow other things like the
+        * console to use them, and to add new ones after the initialisation
+        */
+
+       s3c2410_init_clocks();
+
+       /* add s3c2440 specific clocks */
+
+       s3c2440_clk_cam.parent = clk_get(NULL, "hclk");
+       s3c2440_clk_ac97.parent = clk_get(NULL, "pclk");
 
+       s3c2410_register_clock(&s3c2440_clk_ac97);
+       s3c2410_register_clock(&s3c2440_clk_cam);
 
+       clk_disable(&s3c2440_clk_ac97);
+       clk_disable(&s3c2440_clk_cam);
+
+       /* rename any peripherals used differing from the s3c2410 */
+
+       s3c_device_i2c.name = "s3c2440-i2c";
+}
 
 int __init s3c2440_init(void)
 {
@@ -181,12 +277,15 @@ int __init s3c2440_init(void)
 
        printk("S3C2440: Initialising architecture\n");
 
-       ret = platform_add_devices(uart_devices, ARRAY_SIZE(uart_devices));
-       if (ret)
-               return ret;
+       ret = sysdev_class_register(&s3c2440_sysclass);
+       if (ret == 0)
+               ret = sysdev_register(&s3c2440_sysdev);
 
-       // todo: board specific inits?
+       if (ret != 0)
+               printk(KERN_ERR "failed to register sysdev for s3c2440\n");
+
+       if (ret == 0)
+               ret = platform_add_devices(s3c24xx_uart_devs, s3c2440_uart_count);
 
        return ret;
 }
-
index bf49a66..f2c9234 100644 (file)
  * published by the Free Software Foundation.
  *
  * Modifications:
- *     24-Aug-2004 BJD  Start of S3C2440 CPU support
+ *     24-Aug-2004 BJD  Start of S3C2440 CPU support
+ *     04-Nov-2004 BJD  Added s3c2440_init_uarts()
 */
 
+struct s3c2410_uartcfg;
+
 extern void s3c2440_init_irq(void);
 
 extern void s3c2440_init_time(void);
+
+extern void s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no);
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
index 04ba5df..ccd1604 100644 (file)
@@ -1,7 +1,7 @@
-/* linux/include/asm-arm/arch-s3c2410/time.h
+/* linux/arch/arm/mach-s3c2410/time.c
  *
- *  Copyright (C) 2003 Simtec Electronics <linux@simtec.co.uk>
- *    Ben Dooks, <ben@simtec.co.uk>
+ * 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 as published by
 #include <asm/arch/regs-irq.h>
 #include <asm/mach/time.h>
 
+#include "clock.h"
+
 static unsigned long timer_startval;
-static unsigned long timer_ticks_usec;
+static unsigned long timer_usec_ticks;
 
+#define TIMER_USEC_SHIFT 16
 
-/* with an 12MHz clock, we get 12 ticks per-usec
- */
+/* we use the shifted arithmetic to work out the ratio of timer ticks
+ * to usecs, as often the peripheral clock is not a nice even multiple
+ * of 1MHz.
+ *
+ * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok
+ * for the current HZ value of 200 without producing overflows.
+ *
+ * Original patch by Dimitry Andric, updated by Ben Dooks
+*/
+
+
+/* timer_mask_usec_ticks
+ *
+ * given a clock and divisor, make the value to pass into timer_ticks_to_usec
+ * to scale the ticks into usecs
+*/
+
+static inline unsigned long
+timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk)
+{
+       unsigned long den = pclk / 1000;
 
+       return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den;
+}
+
+/* timer_ticks_to_usec
+ *
+ * convert timer ticks to usec.
+*/
+
+static inline unsigned long timer_ticks_to_usec(unsigned long ticks)
+{
+       unsigned long res;
+
+       res = ticks * timer_usec_ticks;
+       res += 1 << (TIMER_USEC_SHIFT - 4);     /* round up slightly */
+
+       return res >> TIMER_USEC_SHIFT;
+}
 
 /***
  * Returns microsecond  since last clock interrupt.  Note that interrupts
@@ -53,31 +92,31 @@ static unsigned long timer_ticks_usec;
 static unsigned long s3c2410_gettimeoffset (void)
 {
        unsigned long tdone;
-       unsigned long usec;
        unsigned long irqpend;
+       unsigned long tval;
 
        /* work out how many ticks have gone since last timer interrupt */
 
-       tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4));
+        tval =  __raw_readl(S3C2410_TCNTO(4));
+       tdone = timer_startval - tval;
 
        /* check to see if there is an interrupt pending */
 
        irqpend = __raw_readl(S3C2410_SRCPND);
        if (irqpend & SRCPND_TIMER4) {
                /* re-read the timer, and try and fix up for the missed
-                * interrupt */
+                * interrupt. Note, the interrupt may go off before the
+                * timer has re-loaded from wrapping.
+                */
 
-               tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4));
-               tdone += 1<<16;
-       }
-
-       /* currently, tcnt is in 12MHz units, but this may change
-        * for non-bast machines...
-        */
+               tval =  __raw_readl(S3C2410_TCNTO(4));
+               tdone = timer_startval - tval;
 
-       usec = tdone / timer_ticks_usec;
+               if (tval != 0)
+                       tdone += timer_startval;
+       }
 
-       return usec;
+       return timer_ticks_to_usec(tdone);
 }
 
 
@@ -87,13 +126,14 @@ static unsigned long s3c2410_gettimeoffset (void)
 static irqreturn_t
 s3c2410_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 s3c2410_timer_irq = {
-       .name           = "S32410 Timer Tick",
+       .name           = "S3C2410 Timer Tick",
        .flags          = SA_INTERRUPT,
        .handler        = s3c2410_timer_interrupt
 };
@@ -104,15 +144,13 @@ static struct irqaction s3c2410_timer_irq = {
  * Currently we only use timer4, as it is the only timer which has no
  * other function that can be exploited externally
  */
-void __init s3c2410_init_time (void)
+static void s3c2410_timer_setup (void)
 {
        unsigned long tcon;
        unsigned long tcnt;
        unsigned long tcfg1;
        unsigned long tcfg0;
 
-       gettimeoffset = s3c2410_gettimeoffset;
-
        tcnt = 0xffff;  /* default value for tcnt */
 
        /* read the current timer configuration bits */
@@ -124,23 +162,25 @@ void __init s3c2410_init_time (void)
        /* configure the system for whichever machine is in use */
 
        if (machine_is_bast() || machine_is_vr1000()) {
-               timer_ticks_usec = 12;        /* timer is at 12MHz */
-               tcnt = (timer_ticks_usec * (1000*1000)) / HZ;
-       }
+               /* timer is at 12MHz, scaler is 1 */
+               timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
+               tcnt = 12000000 / HZ;
+
+               tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
+               tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
+       } else {
+               /* for the h1940 (and others), we use the pclk from the core
+                * to generate the timer values. since values around 50 to
+                * 70MHz are not values we can directly generate the timer
+                * value from, we need to pre-scale and divide before using it.
+                *
+                * for instance, using 50.7MHz and dividing by 6 gives 8.45MHz
+                * (8.45 ticks per usec)
+                */
 
-       /* for the h1940, we use the pclk from the core to generate
-        * the timer values. since 67.5MHz is not a value we can directly
-        * generate the timer value from, we need to pre-scale and
-        * divied before using it.
-        *
-        * overall divsior to get 200Hz is 337500
-        *   we can fit tcnt if we pre-scale by 6, producing a tick rate
-        *   of 11.25MHz, and a tcnt of 56250.
-        */
+               /* this is used as default if no other timer can be found */
 
-       if (machine_is_h1940() || machine_is_smdk2410() ) {
-               timer_ticks_usec = s3c2410_pclk / (1000*1000);
-               timer_ticks_usec /= 6;
+               timer_usec_ticks = timer_mask_usec_ticks(6, s3c24xx_pclk);
 
                tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
                tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
@@ -148,12 +188,15 @@ void __init s3c2410_init_time (void)
                tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
                tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
 
-               tcnt = (s3c2410_pclk / 6) / HZ;
+               tcnt = (s3c24xx_pclk / 6) / HZ;
        }
 
+       /* timers reload after counting zero, so reduce the count by 1 */
 
-       printk("setup_timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx\n",
-              tcon, tcnt, tcfg0, tcfg1);
+       tcnt--;
+
+       printk("timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
+              tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks);
 
        /* check to see if timer is within 16bit range... */
        if (tcnt > 0xffff) {
@@ -177,13 +220,20 @@ void __init s3c2410_init_time (void)
        __raw_writel(tcnt, S3C2410_TCNTB(4));
        __raw_writel(tcnt, S3C2410_TCMPB(4));
 
-       setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
-
        /* start the timer running */
        tcon |= S3C2410_TCON_T4START;
        tcon &= ~S3C2410_TCON_T4MANUALUPD;
        __raw_writel(tcon, S3C2410_TCON);
 }
 
+static void __init s3c2410_timer_init (void)
+{
+       s3c2410_timer_setup();
+       setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
+}
 
-
+struct sys_timer s3c2410_timer = {
+       .init           = s3c2410_timer_init,
+       .offset         = s3c2410_gettimeoffset,
+       .resume         = s3c2410_timer_setup
+};
index b8f8ded..7f2b613 100644 (file)
@@ -13,6 +13,7 @@
  *
  * Modifications:
  *     14-Sep-2004 BJD  Created
+ *     18-Oct-2004 BJD  Cleanups, and added code to report OC cleared
 */
 
 #define DEBUG
@@ -51,10 +52,8 @@ usb_simtec_powercontrol(int port, int to)
 {
        pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
 
-       if (port == 1) {
+       if (port == 1)
                s3c2410_gpio_setpin(S3C2410_GPB4, to ? 0:1);
-               pr_debug("GPBDAT now %08x\n", __raw_readl(S3C2410_GPBDAT));
-       }
 }
 
 static irqreturn_t
@@ -67,6 +66,7 @@ usb_simtec_ocirq(int irq, void *pw, struct pt_regs *regs)
                s3c2410_report_oc(info, 3);
        } else {
                pr_debug("usb_simtec: over-current irq (oc cleared)\n");
+               s3c2410_report_oc(info, 0);
        }
 
        return IRQ_HANDLED;
@@ -77,16 +77,15 @@ 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);
+                                 "USB Over-current", 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);
+               free_irq(IRQ_USBOC, info);
        }
 }
 
@@ -110,14 +109,5 @@ int usb_simtec_init(void)
 
        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-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
+
index 23bf73e..a85faf7 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 #include <linux/timer.h>
 
 #include <asm/hardware.h>
@@ -31,6 +33,7 @@
 #include <asm/arch/collie.h>
 
 #include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 
@@ -89,6 +92,48 @@ static struct platform_device *devices[] __initdata = {
        &locomo_device,
 };
 
+static struct mtd_partition collie_partitions[] = {
+       {
+               .name           = "bootloader",
+               .offset         = 0,
+               .size           = 0x000C0000,
+               .mask_flags     = MTD_WRITEABLE
+       }, {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 0x00100000,
+       }, {
+               .name           = "rootfs",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 0x00e20000,
+       }
+};
+
+static void collie_set_vpp(int vpp)
+{
+       COLLIE_SCP_REG_GPCR |= COLLIE_SCP_VPEN;
+       if (vpp) {
+               COLLIE_SCP_REG_GPWR |= COLLIE_SCP_VPEN;
+       } else {
+               COLLIE_SCP_REG_GPWR &= ~COLLIE_SCP_VPEN;
+       }
+}
+
+static struct flash_platform_data collie_flash_data = {
+       .map_name       = "cfi_probe",
+       .set_vpp        = collie_set_vpp,
+       .parts          = collie_partitions,
+       .nr_parts       = ARRAY_SIZE(collie_partitions),
+};
+
+static struct resource collie_flash_resources[] = {
+       {
+               .start  = SA1100_CS0_PHYS,
+               .end    = SA1100_CS0_PHYS + SZ_32M - 1,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
 static void __init collie_init(void)
 {
        int ret = 0;
@@ -121,6 +166,9 @@ static void __init collie_init(void)
        if (ret) {
                printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
        }
+
+       sa11x0_set_flash_data(&collie_flash_data, collie_flash_resources,
+                             ARRAY_SIZE(collie_flash_resources));
 }
 
 static struct map_desc collie_io_desc[] __initdata = {
@@ -140,6 +188,6 @@ MACHINE_START(COLLIE, "Sharp-Collie")
        BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
        MAPIO(collie_map_io)
        INITIRQ(sa1100_init_irq)
-       INIT_MACHINE(collie_init)
-       INITTIME(sa1100_init_time)
+       .timer          = &sa1100_timer,
+       .init_machine   = collie_init,
 MACHINE_END
index da426bc..6a27a2d 100644 (file)
@@ -28,11 +28,7 @@ extern void clear_cs3_bit(int value);
 
 void simpad_leds_event(led_event_t evt)
 {
-       unsigned long flags;
-
-       //local_irq_save(flags);
-
-       switch (evt) 
+       switch (evt)
        {
        case led_start:
                hw_led_state = LED_GREEN;
@@ -101,6 +97,5 @@ void simpad_leds_event(led_event_t evt)
                set_cs3_bit(LED2_ON);
        else 
                clear_cs3_bit(LED2_ON);
-       //local_irq_restore(flags);
 }
 
index a747fd0..a231429 100644 (file)
@@ -173,6 +173,8 @@ static int neponset_probe(struct device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+
 /*
  * LDM power management.
  */
@@ -184,12 +186,12 @@ static int neponset_suspend(struct device *dev, u32 state, u32 level)
        if (level == SUSPEND_SAVE_STATE ||
            level == SUSPEND_DISABLE ||
            level == SUSPEND_POWER_DOWN) {
-               if (!dev->saved_state)
-                       dev->saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
-               if (!dev->saved_state)
+               if (!dev->power.saved_state)
+                       dev->power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
+               if (!dev->power.saved_state)
                        return -ENOMEM;
 
-               *(unsigned int *)dev->saved_state = NCR_0;
+               *(unsigned int *)dev->power.saved_state = NCR_0;
        }
 
        return 0;
@@ -198,16 +200,21 @@ static int neponset_suspend(struct device *dev, u32 state, u32 level)
 static int neponset_resume(struct device *dev, u32 level)
 {
        if (level == RESUME_RESTORE_STATE || level == RESUME_ENABLE) {
-               if (dev->saved_state) {
-                       NCR_0 = *(unsigned int *)dev->saved_state;
-                       kfree(dev->saved_state);
-                       dev->saved_state = NULL;
+               if (dev->power.saved_state) {
+                       NCR_0 = *(unsigned int *)dev->power.saved_state;
+                       kfree(dev->power.saved_state);
+                       dev->power.saved_state = NULL;
                }
        }
 
        return 0;
 }
 
+#else
+#define        neponset_suspend        NULL
+#define        neponset_resume NULL
+#endif
+
 static struct device_driver neponset_device_driver = {
        .name           = "neponset",
        .bus            = &platform_bus_type,
index 7120ec5..379ea5e 100644 (file)
@@ -45,9 +45,6 @@ extern void sa1100_cpu_resume(void);
  */
 enum { SLEEP_SAVE_SP = 0,
 
-       SLEEP_SAVE_OIER,
-       SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
-
        SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR,
        SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
 
@@ -57,7 +54,7 @@ enum {        SLEEP_SAVE_SP = 0,
 };
 
 
-static int sa11x0_pm_enter(u32 state)
+static int sa11x0_pm_enter(suspend_state_t state)
 {
        unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE];
        struct timespec delta, rtc;
@@ -72,12 +69,6 @@ static int sa11x0_pm_enter(u32 state)
        gpio = GPLR;
 
        /* save vital registers */
-       SAVE(OSMR0);
-       SAVE(OSMR1);
-       SAVE(OSMR2);
-       SAVE(OSMR3);
-       SAVE(OIER);
-
        SAVE(GPDR);
        SAVE(GAFR);
 
@@ -129,15 +120,6 @@ static int sa11x0_pm_enter(u32 state)
         */
        PSSR = PSSR_PH;
 
-       RESTORE(OSMR0);
-       RESTORE(OSMR1);
-       RESTORE(OSMR2);
-       RESTORE(OSMR3);
-       RESTORE(OIER);
-
-       /* OSMR0 is the system timer: make sure OSCR is sufficiently behind */
-       OSCR = OSMR0 - LATCH;
-
        /* restore current time */
        rtc.tv_sec = RCNR;
        restore_time_delta(&delta, &rtc);
@@ -153,7 +135,7 @@ unsigned long sleep_phys_sp(void *sp)
 /*
  * Called after processes are frozen, but before we shut down devices.
  */
-static int sa11x0_pm_prepare(u32 state)
+static int sa11x0_pm_prepare(suspend_state_t state)
 {
        return 0;
 }
@@ -161,7 +143,7 @@ static int sa11x0_pm_prepare(u32 state)
 /*
  * Called after devices are re-setup, but before processes are thawed.
  */
-static int sa11x0_pm_finish(u32 state)
+static int sa11x0_pm_finish(suspend_state_t state)
 {
        return 0;
 }
index 03b8af5..2fa1e28 100644 (file)
@@ -70,12 +70,12 @@ ENTRY(sa1100_cpu_suspend)
        @ delay 90us and set CPU PLL to lowest speed
        @ fixes resume problem on high speed SA1110
        mov     r0, #90
-       bl      udelay
+       bl      __udelay
        ldr     r0, =PPCR
        mov     r1, #0
        str     r1, [r0]
        mov     r0, #90
-       bl      udelay
+       bl      __udelay
 
        /*
         * SA1110 SDRAM controller workaround.  register values:
index 1c3d082..19b0c0f 100644 (file)
@@ -84,12 +84,16 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        unsigned int next_match;
 
+       write_seqlock(&xtime_lock);
+
        do {
                timer_tick(regs);
                OSSR = OSSR_M0;  /* Clear match on timer 0 */
                next_match = (OSMR0 += LATCH);
        } while ((signed long)(next_match - OSCR) <= 0);
 
+       write_sequnlock(&xtime_lock);
+
        return IRQ_HANDLED;
 }
 
@@ -99,11 +103,10 @@ static struct irqaction sa1100_timer_irq = {
        .handler        = sa1100_timer_interrupt
 };
 
-void __init sa1100_init_time(void)
+static void __init sa1100_timer_init(void)
 {
        struct timespec tv;
 
-       gettimeoffset = sa1100_gettimeoffset;
        set_rtc = sa1100_set_rtc;
 
        tv.tv_nsec = 0;
@@ -117,3 +120,40 @@ void __init sa1100_init_time(void)
        OSCR = 0;               /* initialize free-running timer, force first match */
 }
 
+#ifdef CONFIG_PM
+unsigned long osmr[4], oier;
+
+static void sa1100_timer_suspend(void)
+{
+       osmr[0] = OSMR0;
+       osmr[1] = OSMR1;
+       osmr[2] = OSMR2;
+       osmr[3] = OSMR3;
+       oier = OIER;
+}
+
+static void sa1100_timer_resume(void)
+{
+       OSSR = 0x0f;
+       OSMR0 = osmr[0];
+       OSMR1 = osmr[1];
+       OSMR2 = osmr[2];
+       OSMR3 = osmr[3];
+       OIER = oier;
+
+       /*
+        * OSMR0 is the system timer: make sure OSCR is sufficiently behind
+        */
+       OSCR = OSMR0 - LATCH;
+}
+#else
+#define sa1100_timer_suspend NULL
+#define sa1100_timer_resume NULL
+#endif
+
+struct sys_timer sa1100_timer = {
+       .init           = sa1100_timer_init,
+       .suspend        = sa1100_timer_suspend,
+       .resume         = sa1100_timer_resume,
+       .offset         = sa1100_gettimeoffset,
+};
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
index 402dad2..76dcfc9 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/pgtable.h>
 #include <asm/shmparam.h>
 #include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
 
 #if SHMLBA > 16384
 #error FIX ME
index 3bddde0..272d45e 100644 (file)
@@ -138,7 +138,7 @@ __arm710_setup:     mov     r0, #0
                bic     r0, r0, #0x0e00                 @ ..V. ..RS BLDP WCAM
                orr     r0, r0, #0x0100                 @ .... .... .111 .... (old)
                orr     r0, r0, #0x003d                 @ .... ..01 ..11 1101 (new)
-               mov     pc, lr                          @ __ret (head-armv.S)
+               mov     pc, lr                          @ __ret (head.S)
                .size   __arm710_setup, . - __arm710_setup
 
                .type   __arm720_setup, #function
@@ -153,7 +153,7 @@ __arm720_setup:     mov     r0, #0
                bic     r0, r0, #0x0e00                 @ ..V. ..RS BLDP WCAM
                orr     r0, r0, #0x2100                 @ .... .... .111 .... (old)
                orr     r0, r0, #0x003d                 @ ..1. ..01 ..11 1101 (new)
-               mov     pc, lr                          @ __ret (head-armv.S)
+               mov     pc, lr                          @ __ret (head.S)
                .size   __arm720_setup, . - __arm720_setup
 
                __INITDATA
index 0a4ff26..fa3a5dd 100644 (file)
@@ -201,6 +201,11 @@ __v6_setup:
        mov     r10, #0x1f                      @ domains 0, 1 = manager
        mcr     p15, 0, r10, c3, c0, 0          @ load domain access register
        mrc     p15, 0, r0, c1, c0, 0           @ read control register
+#ifdef CONFIG_VFP
+       mrc     p15, 0, r10, c1, c0, 2
+       orr     r10, r10, #(3 << 20)
+       mcr     p15, 0, r10, c1, c0, 2          @ Enable full access to VFP
+#endif
        ldr     r10, cr1_clear                  @ get mask for bits to clear
        bic     r0, r0, r10                     @ clear bits them
        ldr     r10, cr1_set                    @ get mask for bits to set
@@ -250,8 +255,8 @@ cpu_elf_name:
         */
        .type   __v6_proc_info, #object
 __v6_proc_info:
-       .long   0x00070000
-       .long   0x00ff0000
+       .long   0x0007b000
+       .long   0x0007f000
        .long   0x00000c0e
        b       __v6_setup
        .long   cpu_arch_name
index a1dc5ee..7ffd8cb 100644 (file)
@@ -75,7 +75,11 @@ static float64 float64_mnf(float64 rFm)
        union float64_components u;
 
        u.f64 = rFm;
+#ifdef __ARMEB__
+       u.i[0] ^= 0x80000000;
+#else
        u.i[1] ^= 0x80000000;
+#endif
 
        return u.f64;
 }
@@ -85,7 +89,11 @@ static float64 float64_abs(float64 rFm)
        union float64_components u;
 
        u.f64 = rFm;
+#ifdef __ARMEB__
+       u.i[0] &= 0x7fffffff;
+#else
        u.i[1] &= 0x7fffffff;
+#endif
 
        return u.f64;
 }
index 98e0f52..55a02bc 100644 (file)
@@ -249,6 +249,12 @@ struct vfp_double {
        u64     significand;
 };
 
+/*
+ * VFP_REG_ZERO is a special register number for vfp_get_double
+ * which returns (double)0.0.  This is useful for the compare with
+ * zero instructions.
+ */
+#define VFP_REG_ZERO   16
 extern u64 vfp_get_double(unsigned int reg);
 extern void vfp_put_double(unsigned int reg, u64 val);
 
@@ -331,3 +337,8 @@ extern u32 vfp_get_sys(unsigned int reg);
 extern void vfp_put_sys(unsigned int reg, u32 val);
 
 u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
+
+/*
+ * A special flag to tell the normalisation code not to normalise.
+ */
+#define VFP_NAN_FLAG   0x100
index 54649c1..fa3053e 100644 (file)
@@ -31,7 +31,7 @@
  * ===========================================================================
  */
 #include <linux/kernel.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/ptrace.h>
 #include <asm/vfp.h>
 
@@ -195,7 +195,7 @@ u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exce
                         dd, d, exceptions);
                vfp_put_double(dd, d);
        }
-       return exceptions;
+       return exceptions & ~VFP_NAN_FLAG;
 }
 
 /*
@@ -240,7 +240,7 @@ vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
        /*
         * If one was a signalling NAN, raise invalid operation.
         */
-       return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : 0x100;
+       return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
 }
 
 /*
@@ -427,12 +427,12 @@ static u32 vfp_double_fcmpe(int dd, int unused, int dm, u32 fpscr)
 
 static u32 vfp_double_fcmpz(int dd, int unused, int dm, u32 fpscr)
 {
-       return vfp_compare(dd, 0, -1, fpscr);
+       return vfp_compare(dd, 0, VFP_REG_ZERO, fpscr);
 }
 
 static u32 vfp_double_fcmpez(int dd, int unused, int dm, u32 fpscr)
 {
-       return vfp_compare(dd, 1, -1, fpscr);
+       return vfp_compare(dd, 1, VFP_REG_ZERO, fpscr);
 }
 
 static u32 vfp_double_fcvts(int sd, int unused, int dm, u32 fpscr)
index ad36261..0dcfa8a 100644 (file)
@@ -199,6 +199,11 @@ vfp_get_double:
        mov     pc, lr
        .endr
 
+       @ virtual register 16 for compare with zero
+       mov     r0, #0
+       mov     r1, #0
+       mov     pc, lr
+
        .globl  vfp_put_double
 vfp_put_double:
        mov     r0, r0, lsr #1
index 92aa841..6849fe3 100644 (file)
@@ -31,7 +31,7 @@
  * ===========================================================================
  */
 #include <linux/kernel.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/ptrace.h>
 #include <asm/vfp.h>
 
@@ -201,7 +201,7 @@ u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exce
                vfp_put_float(sd, d);
        }
 
-       return exceptions;
+       return exceptions & ~VFP_NAN_FLAG;
 }
 
 /*
@@ -246,7 +246,7 @@ vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
        /*
         * If one was a signalling NAN, raise invalid operation.
         */
-       return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : 0x100;
+       return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
 }
 
 
index dbbc214..a7a18c4 100644 (file)
@@ -166,6 +166,9 @@ EXPORT_SYMBOL(do_settimeofday);
 static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
         do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
         do_set_rtc(); //FIME - EVERY timer IRQ?
         profile_tick(CPU_PROFILING, regs);
        return IRQ_HANDLED; //FIXME - is this right?
index 44090c4..0d8ea19 100644 (file)
@@ -47,7 +47,7 @@ static void arc_floppy_data_enable_dma(dmach_t channel, dma_t *dma)
                        &fdc1772_dma_read_end - &fdc1772_dma_read);
                fdc1772_setupdma(dma->buf.length, dma->buf.__address); /* Sets data pointer up */
                enable_fiq(FIQ_FLOPPYDATA);
-               loacl_irq_restore(flags);
+               local_irq_restore(flags);
           }
           break;
 
index 3cbeffa..78e9198 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/smp.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/pgtable.h>
 
 #define PEDANTIC
index 9864aad..f42918b 100644 (file)
@@ -1,15 +1,11 @@
 menu "Kernel hacking"
 
-source "lib/Kconfig.debug"
-
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-config PROFILE
+config PROFILING
        bool "Kernel profiling support"
 
-config PROFILE_SHIFT
-       int "Profile shift count"
-       depends on PROFILE
-       default "2"
+config SYSTEM_PROFILER
+        bool "System profiling support"
 
 config ETRAX_KGDB
        bool "Use kernel GDB debugger"
@@ -25,4 +21,21 @@ config ETRAX_KGDB
          didn't before).  The kernel halts when it boots, waiting for gdb if
          this option is turned on!
 
+
+config DEBUG_INFO
+        bool "Compile the kernel with debug info"
+        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 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
index 20a5608..5276160 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.4 2003/07/04 12:57:13 tobiasa Exp $
+# $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
@@ -11,6 +11,7 @@ obj-y   := entry.o traps.o shadows.o debugport.o irq.o \
 
 obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
 obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
+obj-$(CONFIG_MODULES)    += crisksyms.o
 
 clean:
 
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);
index c5e6348..b2f16d6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.1 2002/12/11 15:42:02 starvik Exp $
+/* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $
  *
  *     linux/arch/cris/kernel/irq.c
  *
@@ -23,12 +23,8 @@ irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq pro
  */
 
 void
-set_int_vector(int n, irqvectptr addr, irqvectptr saddr)
+set_int_vector(int n, irqvectptr addr)
 {
-       /* remember the shortcut entry point, after the prologue */
-
-       irq_shortcuts[n] = saddr;
-
        etrax_irv->v[n + 0x20] = (irqvectptr)addr;
 }
 
@@ -106,17 +102,6 @@ static void (*interrupt[NR_IRQS])(void) = {
        IRQ31_interrupt
 };
 
-static void (*sinterrupt[NR_IRQS])(void) = {
-       NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt,
-       sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt,
-       sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt,
-       sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL, 
-       sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt, 
-       sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt, 
-       sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL,
-       sIRQ31_interrupt
-};
-
 static void (*bad_interrupt[NR_IRQS])(void) = {
         NULL, NULL,
        NULL, bad_IRQ3_interrupt,
@@ -137,12 +122,12 @@ static void (*bad_interrupt[NR_IRQS])(void) = {
 
 void arch_setup_irq(int irq)
 {
-  set_int_vector(irq, interrupt[irq], sinterrupt[irq]);
+  set_int_vector(irq, interrupt[irq]);
 }
 
 void arch_free_irq(int irq)
 {
-  set_int_vector(irq, bad_interrupt[irq], 0);
+  set_int_vector(irq, bad_interrupt[irq]);
 }
 
 void weird_irq(void);
@@ -187,20 +172,20 @@ init_IRQ(void)
         
        /* set all etrax irq's to the bad handlers */
        for (i = 2; i < NR_IRQS; i++)
-               set_int_vector(i, bad_interrupt[i], 0);
+               set_int_vector(i, bad_interrupt[i]);
         
        /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
 
-       set_int_vector(15, multiple_interrupt, 0);
+       set_int_vector(15, multiple_interrupt);
        
        /* 0 and 1 which are special breakpoint/NMI traps */
 
-       set_int_vector(0, hwbreakpoint, 0);
-       set_int_vector(1, IRQ1_interrupt, 0);
+       set_int_vector(0, hwbreakpoint);
+       set_int_vector(1, IRQ1_interrupt);
 
        /* and irq 14 which is the mmu bus fault handler */
 
-       set_int_vector(14, mmu_bus_fault, 0);
+       set_int_vector(14, mmu_bus_fault);
 
        /* setup the system-call trap, which is reached by BREAK 13 */
 
index 4e5d50d..7d368c8 100644 (file)
@@ -18,6 +18,9 @@
 *! Jul 21 1999  Bjorn Wesen     eLinux port
 *!
 *! $Log: kgdb.c,v $
+*! Revision 1.5  2004/10/07 13:59:08  starvik
+*! Corrected call to set_int_vector
+*!
 *! Revision 1.4  2003/04/09 05:20:44  starvik
 *! Merge of Linux 2.5.67
 *!
@@ -68,7 +71,7 @@
 *!
 *!---------------------------------------------------------------------------
 *!
-*! $Id: kgdb.c,v 1.4 2003/04/09 05:20:44 starvik Exp $
+*! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $
 *!
 *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
 *!
@@ -1557,7 +1560,7 @@ kgdb_init(void)
        /* could initialize debug port as well but it's done in head.S already... */
 
         /* breakpoint handler is now set in irq.c */
-       set_int_vector(8, kgdb_handle_serial, 0);
+       set_int_vector(8, kgdb_handle_serial);
        
        enableDebugIRQ();
 }
index 9e134c6..71ba736 100644 (file)
@@ -26,6 +26,7 @@ SECTIONS
        .text : {
                *(.text)
                SCHED_TEXT
+               LOCK_TEXT
                *(.fixup)
                *(.text.__*)
        }
index 0b293d6..8a60021 100644 (file)
@@ -46,6 +46,9 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
        platform_timer_eoi();
 
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
        profile_tick(CPU_PROFILING, regs);
 }
 
index 0900778..65748bf 100644 (file)
@@ -181,7 +181,7 @@ __command_line:
        .long   __start
        .long   __start
 vector =       2
-       .rept   126-1
+       .rept   126
        .long   _interrupt_redirect_table+vector*4
 vector =       vector + 1
        .endr
index e8a0471..7b73c67 100644 (file)
@@ -61,7 +61,6 @@
 #define r3  edx
 #define r4  esi
 #define r5  edi
-#define r6  ebp
 
 #define eaxl  al
 #define eaxh  ah
 // output registers r0, r1, r4 or r5.  
 
 // Parameters:
+// table table base address
 //   %1  out_state[0]
 //   %2  out_state[1]
 //   %3  out_state[2]
 //   %4  out_state[3]
-//   %5  table base address
-//   %6  input register for the round (destroyed)
-//   %7  scratch register for the round
-
-#define do_col(a1, a2, a3, a4, a5, a6, a7)     \
-       movzx   %l(a6),%a7;                     \
-       xor     a5(,%a7,4),%a1;                 \
-       movzx   %h(a6),%a7;                     \
-       shr     $16,%a6;                        \
-       xor     a5+tlen(,%a7,4),%a2;            \
-       movzx   %l(a6),%a7;                     \
-       movzx   %h(a6),%a6;                     \
-       xor     a5+2*tlen(,%a7,4),%a3;          \
-       xor     a5+3*tlen(,%a6,4),%a4;
+//   idx input register for the round (destroyed)
+//   tmp scratch register for the round
+// sched key schedule
+
+#define do_col(table, a1,a2,a3,a4, idx, tmp)   \
+       movzx   %l(idx),%tmp;                   \
+       xor     table(,%tmp,4),%a1;             \
+       movzx   %h(idx),%tmp;                   \
+       shr     $16,%idx;                       \
+       xor     table+tlen(,%tmp,4),%a2;        \
+       movzx   %l(idx),%tmp;                   \
+       movzx   %h(idx),%idx;                   \
+       xor     table+2*tlen(,%tmp,4),%a3;      \
+       xor     table+3*tlen(,%idx,4),%a4;
 
 // initialise output registers from the key schedule
-
-#define do_fcol(a1, a2, a3, a4, a5, a6, a7, a8)        \
-       mov     0 a8,%a1;                       \
-       movzx   %l(a6),%a7;                     \
-       mov     12 a8,%a2;                      \
-       xor     a5(,%a7,4),%a1;                 \
-       mov     4 a8,%a4;                       \
-       movzx   %h(a6),%a7;                     \
-       shr     $16,%a6;                        \
-       xor     a5+tlen(,%a7,4),%a2;            \
-       movzx   %l(a6),%a7;                     \
-       movzx   %h(a6),%a6;                     \
-       xor     a5+3*tlen(,%a6,4),%a4;          \
-       mov     %a3,%a6;                        \
-       mov     8 a8,%a3;                       \
-       xor     a5+2*tlen(,%a7,4),%a3;
+// NB1: original value of a3 is in idx on exit
+// NB2: original values of a1,a2,a4 aren't used
+#define do_fcol(table, a1,a2,a3,a4, idx, tmp, sched) \
+       mov     0 sched,%a1;                    \
+       movzx   %l(idx),%tmp;                   \
+       mov     12 sched,%a2;                   \
+       xor     table(,%tmp,4),%a1;             \
+       mov     4 sched,%a4;                    \
+       movzx   %h(idx),%tmp;                   \
+       shr     $16,%idx;                       \
+       xor     table+tlen(,%tmp,4),%a2;        \
+       movzx   %l(idx),%tmp;                   \
+       movzx   %h(idx),%idx;                   \
+       xor     table+3*tlen(,%idx,4),%a4;      \
+       mov     %a3,%idx;                       \
+       mov     8 sched,%a3;                    \
+       xor     table+2*tlen(,%tmp,4),%a3;
 
 // initialise output registers from the key schedule
-
-#define do_icol(a1, a2, a3, a4, a5, a6, a7, a8)        \
-       mov     0 a8,%a1;                       \
-       movzx   %l(a6),%a7;                     \
-       mov     4 a8,%a2;                       \
-       xor     a5(,%a7,4),%a1;                 \
-       mov     12 a8,%a4;                      \
-       movzx   %h(a6),%a7;                     \
-       shr     $16,%a6;                        \
-       xor     a5+tlen(,%a7,4),%a2;            \
-       movzx   %l(a6),%a7;                     \
-       movzx   %h(a6),%a6;                     \
-       xor     a5+3*tlen(,%a6,4),%a4;          \
-       mov     %a3,%a6;                        \
-       mov     8 a8,%a3;                       \
-       xor     a5+2*tlen(,%a7,4),%a3;
+// NB1: original value of a3 is in idx on exit
+// NB2: original values of a1,a2,a4 aren't used
+#define do_icol(table, a1,a2,a3,a4, idx, tmp, sched) \
+       mov     0 sched,%a1;                    \
+       movzx   %l(idx),%tmp;                   \
+       mov     4 sched,%a2;                    \
+       xor     table(,%tmp,4),%a1;             \
+       mov     12 sched,%a4;                   \
+       movzx   %h(idx),%tmp;                   \
+       shr     $16,%idx;                       \
+       xor     table+tlen(,%tmp,4),%a2;        \
+       movzx   %l(idx),%tmp;                   \
+       movzx   %h(idx),%idx;                   \
+       xor     table+3*tlen(,%idx,4),%a4;      \
+       mov     %a3,%idx;                       \
+       mov     8 sched,%a3;                    \
+       xor     table+2*tlen(,%tmp,4),%a3;
 
 
 // original Gladman had conditional saves to MMX regs.
 #define restore(a1, a2)                \
        mov     4*a2(%esp),%a1
 
-// This macro performs a forward encryption cycle. It is entered with
-// the first previous round column values in r0, r1, r4 and r5 and
-// exits with the final values in the same registers, using the MMX
-// registers mm0-mm1 or the stack for temporary storage
-
-// mov current column values into the MMX registers
-#define fwd_rnd(arg, table)                                    \
-       /* mov current column values into the MMX registers */  \
-       mov     %r0,%r2;                                        \
-       save   (0,r1);                                          \
-       save   (1,r5);                                          \
-                                                               \
-       /* compute new column values */                         \
-       do_fcol(r0,r5,r4,r1,table, r2,r3, arg);                 \
-       do_col (r4,r1,r0,r5,table, r2,r3);                      \
-       restore(r2,0);                                          \
-       do_col (r1,r0,r5,r4,table, r2,r3);                      \
-       restore(r2,1);                                          \
-       do_col (r5,r4,r1,r0,table, r2,r3);
-
-// This macro performs an inverse encryption cycle. It is entered with
-// the first previous round column values in r0, r1, r4 and r5 and
-// exits with the final values in the same registers, using the MMX
-// registers mm0-mm1 or the stack for temporary storage
-
-#define inv_rnd(arg, table)                                    \
-       /* mov current column values into the MMX registers */  \
-       mov     %r0,%r2;                                        \
-       save    (0,r1);                                         \
-       save    (1,r5);                                         \
-                                                               \
-       /* compute new column values */                         \
-       do_icol(r0,r1,r4,r5, table, r2,r3, arg);                \
-       do_col (r4,r5,r0,r1, table, r2,r3);                     \
-       restore(r2,0);                                          \
-       do_col (r1,r4,r5,r0, table, r2,r3);                     \
-       restore(r2,1);                                          \
-       do_col (r5,r0,r1,r4, table, r2,r3);
+// These macros perform a forward encryption cycle. They are entered with
+// the first previous round column values in r0,r1,r4,r5 and
+// exit with the final values in the same registers, using stack
+// for temporary storage.
+
+// round column values
+// on entry: r0,r1,r4,r5
+// on exit:  r2,r1,r4,r5
+#define fwd_rnd1(arg, table)                                           \
+       save   (0,r1);                                                  \
+       save   (1,r5);                                                  \
+                                                                       \
+       /* compute new column values */                                 \
+       do_fcol(table, r2,r5,r4,r1, r0,r3, arg);        /* idx=r0 */    \
+       do_col (table, r4,r1,r2,r5, r0,r3);             /* idx=r4 */    \
+       restore(r0,0);                                                  \
+       do_col (table, r1,r2,r5,r4, r0,r3);             /* idx=r1 */    \
+       restore(r0,1);                                                  \
+       do_col (table, r5,r4,r1,r2, r0,r3);             /* idx=r5 */
+
+// round column values
+// on entry: r2,r1,r4,r5
+// on exit:  r0,r1,r4,r5
+#define fwd_rnd2(arg, table)                                           \
+       save   (0,r1);                                                  \
+       save   (1,r5);                                                  \
+                                                                       \
+       /* compute new column values */                                 \
+       do_fcol(table, r0,r5,r4,r1, r2,r3, arg);        /* idx=r2 */    \
+       do_col (table, r4,r1,r0,r5, r2,r3);             /* idx=r4 */    \
+       restore(r2,0);                                                  \
+       do_col (table, r1,r0,r5,r4, r2,r3);             /* idx=r1 */    \
+       restore(r2,1);                                                  \
+       do_col (table, r5,r4,r1,r0, r2,r3);             /* idx=r5 */
+
+// These macros performs an inverse encryption cycle. They are entered with
+// the first previous round column values in r0,r1,r4,r5 and
+// exit with the final values in the same registers, using stack
+// for temporary storage
+
+// round column values
+// on entry: r0,r1,r4,r5
+// on exit:  r2,r1,r4,r5
+#define inv_rnd1(arg, table)                                           \
+       save    (0,r1);                                                 \
+       save    (1,r5);                                                 \
+                                                                       \
+       /* compute new column values */                                 \
+       do_icol(table, r2,r1,r4,r5, r0,r3, arg);        /* idx=r0 */    \
+       do_col (table, r4,r5,r2,r1, r0,r3);             /* idx=r4 */    \
+       restore(r0,0);                                                  \
+       do_col (table, r1,r4,r5,r2, r0,r3);             /* idx=r1 */    \
+       restore(r0,1);                                                  \
+       do_col (table, r5,r2,r1,r4, r0,r3);             /* idx=r5 */
+
+// round column values
+// on entry: r2,r1,r4,r5
+// on exit:  r0,r1,r4,r5
+#define inv_rnd2(arg, table)                                           \
+       save    (0,r1);                                                 \
+       save    (1,r5);                                                 \
+                                                                       \
+       /* compute new column values */                                 \
+       do_icol(table, r0,r1,r4,r5, r2,r3, arg);        /* idx=r2 */    \
+       do_col (table, r4,r5,r0,r1, r2,r3);             /* idx=r4 */    \
+       restore(r2,0);                                                  \
+       do_col (table, r1,r4,r5,r0, r2,r3);             /* idx=r1 */    \
+       restore(r2,1);                                                  \
+       do_col (table, r5,r0,r1,r4, r2,r3);             /* idx=r5 */
 
 // AES (Rijndael) Encryption Subroutine
 
 aes_enc_blk:
        push    %ebp
        mov     ctx(%esp),%ebp      // pointer to context
-       xor     %eax,%eax
 
 // CAUTION: the order and the values used in these assigns 
 // rely on the register mappings
@@ -208,7 +240,9 @@ aes_enc_blk:
        push    %esi
        mov     nrnd(%ebp),%r3   // number of rounds
        push    %edi
-       lea     ekey(%ebp),%r6   // key pointer
+#if ekey != 0
+       lea     ekey(%ebp),%ebp  // key pointer
+#endif
 
 // input four columns and xor in first round key
 
@@ -216,47 +250,47 @@ aes_enc_blk:
        mov     4(%r2),%r1
        mov     8(%r2),%r4
        mov     12(%r2),%r5
-       xor     (%r6),%r0
-       xor     4(%r6),%r1
-       xor     8(%r6),%r4
-       xor     12(%r6),%r5
+       xor     (%ebp),%r0
+       xor     4(%ebp),%r1
+       xor     8(%ebp),%r4
+       xor     12(%ebp),%r5
 
        sub     $8,%esp           // space for register saves on stack
-       add     $16,%r6           // increment to next round key   
+       add     $16,%ebp          // increment to next round key
        sub     $10,%r3          
        je      4f              // 10 rounds for 128-bit key
-       add     $32,%r6
+       add     $32,%ebp
        sub     $2,%r3
        je      3f              // 12 rounds for 128-bit key
-       add     $32,%r6
-
-2:     fwd_rnd( -64(%r6) ,ft_tab)      // 14 rounds for 128-bit key
-       fwd_rnd( -48(%r6) ,ft_tab)
-3:     fwd_rnd( -32(%r6) ,ft_tab)      // 12 rounds for 128-bit key
-       fwd_rnd( -16(%r6) ,ft_tab)
-4:     fwd_rnd(    (%r6) ,ft_tab)      // 10 rounds for 128-bit key
-       fwd_rnd( +16(%r6) ,ft_tab)
-       fwd_rnd( +32(%r6) ,ft_tab)
-       fwd_rnd( +48(%r6) ,ft_tab)
-       fwd_rnd( +64(%r6) ,ft_tab)
-       fwd_rnd( +80(%r6) ,ft_tab)
-       fwd_rnd( +96(%r6) ,ft_tab)
-       fwd_rnd(+112(%r6) ,ft_tab)
-       fwd_rnd(+128(%r6) ,ft_tab)
-       fwd_rnd(+144(%r6) ,fl_tab)      // last round uses a different table
+       add     $32,%ebp
+
+2:     fwd_rnd1( -64(%ebp) ,ft_tab)    // 14 rounds for 128-bit key
+       fwd_rnd2( -48(%ebp) ,ft_tab)
+3:     fwd_rnd1( -32(%ebp) ,ft_tab)    // 12 rounds for 128-bit key
+       fwd_rnd2( -16(%ebp) ,ft_tab)
+4:     fwd_rnd1(    (%ebp) ,ft_tab)    // 10 rounds for 128-bit key
+       fwd_rnd2( +16(%ebp) ,ft_tab)
+       fwd_rnd1( +32(%ebp) ,ft_tab)
+       fwd_rnd2( +48(%ebp) ,ft_tab)
+       fwd_rnd1( +64(%ebp) ,ft_tab)
+       fwd_rnd2( +80(%ebp) ,ft_tab)
+       fwd_rnd1( +96(%ebp) ,ft_tab)
+       fwd_rnd2(+112(%ebp) ,ft_tab)
+       fwd_rnd1(+128(%ebp) ,ft_tab)
+       fwd_rnd2(+144(%ebp) ,fl_tab)    // last round uses a different table
 
 // move final values to the output array.  CAUTION: the 
 // order of these assigns rely on the register mappings
 
        add     $8,%esp
-       mov     out_blk+12(%esp),%r6
-       mov     %r5,12(%r6)
+       mov     out_blk+12(%esp),%ebp
+       mov     %r5,12(%ebp)
        pop     %edi
-       mov     %r4,8(%r6)
+       mov     %r4,8(%ebp)
        pop     %esi
-       mov     %r1,4(%r6)
+       mov     %r1,4(%ebp)
        pop     %ebx
-       mov     %r0,(%r6)
+       mov     %r0,(%ebp)
        pop     %ebp
        mov     $1,%eax
        ret
@@ -273,7 +307,6 @@ aes_enc_blk:
 aes_dec_blk:
        push    %ebp
        mov     ctx(%esp),%ebp       // pointer to context
-       xor     %eax,%eax
 
 // CAUTION: the order and the values used in these assigns 
 // rely on the register mappings
@@ -283,10 +316,12 @@ aes_dec_blk:
        push    %esi
        mov     nrnd(%ebp),%r3   // number of rounds
        push    %edi
-       lea     dkey(%ebp),%r6   // key pointer
+#if dkey != 0
+       lea     dkey(%ebp),%ebp  // key pointer
+#endif
        mov     %r3,%r0
        shl     $4,%r0
-       add     %r0,%r6
+       add     %r0,%ebp
        
 // input four columns and xor in first round key
 
@@ -294,47 +329,47 @@ aes_dec_blk:
        mov     4(%r2),%r1
        mov     8(%r2),%r4
        mov     12(%r2),%r5
-       xor     (%r6),%r0
-       xor     4(%r6),%r1
-       xor     8(%r6),%r4
-       xor     12(%r6),%r5
+       xor     (%ebp),%r0
+       xor     4(%ebp),%r1
+       xor     8(%ebp),%r4
+       xor     12(%ebp),%r5
 
-       sub     $8,%esp           // space for register saves on stack
-       sub     $16,%r6           // increment to next round key   
+       sub     $8,%esp         // space for register saves on stack
+       sub     $16,%ebp        // increment to next round key
        sub     $10,%r3          
        je      4f              // 10 rounds for 128-bit key
-       sub     $32,%r6
+       sub     $32,%ebp
        sub     $2,%r3
        je      3f              // 12 rounds for 128-bit key
-       sub     $32,%r6
-
-2:     inv_rnd( +64(%r6), it_tab)      // 14 rounds for 128-bit key 
-       inv_rnd( +48(%r6), it_tab)
-3:     inv_rnd( +32(%r6), it_tab)      // 12 rounds for 128-bit key
-       inv_rnd( +16(%r6), it_tab)
-4:     inv_rnd(    (%r6), it_tab)      // 10 rounds for 128-bit key
-       inv_rnd( -16(%r6), it_tab)
-       inv_rnd( -32(%r6), it_tab)
-       inv_rnd( -48(%r6), it_tab)
-       inv_rnd( -64(%r6), it_tab)
-       inv_rnd( -80(%r6), it_tab)
-       inv_rnd( -96(%r6), it_tab)
-       inv_rnd(-112(%r6), it_tab)
-       inv_rnd(-128(%r6), it_tab)
-       inv_rnd(-144(%r6), il_tab)      // last round uses a different table
+       sub     $32,%ebp
+
+2:     inv_rnd1( +64(%ebp), it_tab)    // 14 rounds for 128-bit key
+       inv_rnd2( +48(%ebp), it_tab)
+3:     inv_rnd1( +32(%ebp), it_tab)    // 12 rounds for 128-bit key
+       inv_rnd2( +16(%ebp), it_tab)
+4:     inv_rnd1(    (%ebp), it_tab)    // 10 rounds for 128-bit key
+       inv_rnd2( -16(%ebp), it_tab)
+       inv_rnd1( -32(%ebp), it_tab)
+       inv_rnd2( -48(%ebp), it_tab)
+       inv_rnd1( -64(%ebp), it_tab)
+       inv_rnd2( -80(%ebp), it_tab)
+       inv_rnd1( -96(%ebp), it_tab)
+       inv_rnd2(-112(%ebp), it_tab)
+       inv_rnd1(-128(%ebp), it_tab)
+       inv_rnd2(-144(%ebp), il_tab)    // last round uses a different table
 
 // move final values to the output array.  CAUTION: the 
 // order of these assigns rely on the register mappings
 
        add     $8,%esp
-       mov     out_blk+12(%esp),%r6
-       mov     %r5,12(%r6)
+       mov     out_blk+12(%esp),%ebp
+       mov     %r5,12(%ebp)
        pop     %edi
-       mov     %r4,8(%r6)
+       mov     %r4,8(%ebp)
        pop     %esi
-       mov     %r1,4(%r6)
+       mov     %r1,4(%ebp)
        pop     %ebx
-       mov     %r0,(%r6)
+       mov     %r0,(%ebp)
        pop     %ebp
        mov     $1,%eax
        ret
index 2cf76a9..ee75cb2 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_ACPI_BOOT)                := boot.o
+obj-$(CONFIG_X86_IO_APIC)      += earlyquirk.o
 obj-$(CONFIG_ACPI_SLEEP)       += sleep.o wakeup.o
 
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; 
+                       } 
+                       
+               }
+       }
+}
index 5cd4442..32bcd8e 100644 (file)
@@ -4,18 +4,6 @@
 
 menu "CPU Frequency scaling"
 
-config CPU_FREQ
-       bool "CPU Frequency scaling"
-       help
-         Clock scaling allows you to change the clock speed of CPUs on the
-         fly. This is a nice method to save battery power on notebooks,
-         because the lower the clock speed, the less power the CPU consumes.
-
-         For more information, take a look at <file:Documentation/cpu-freq/>
-         or at <http://www.codemonkey.org.uk/projects/cpufreq/>
-
-         If in doubt, say N.
-
 source "drivers/cpufreq/Kconfig"
 
 config CPU_FREQ_TABLE
@@ -42,16 +30,6 @@ config X86_ACPI_CPUFREQ
 
          If in doubt, say N.
 
-config X86_ACPI_CPUFREQ_PROC_INTF
-        bool "/proc/acpi/processor/../performance interface (deprecated)"
-       depends on X86_ACPI_CPUFREQ && PROC_FS
-       help
-         This enables the deprecated /proc/acpi/processor/../performance 
-         interface. While it is helpful for debugging, the generic,
-         cross-architecture cpufreq interfaces should be used.
-
-         If in doubt, say N.
-
 config ELAN_CPUFREQ
        tristate "AMD Elan"
        depends on CPU_FREQ_TABLE && X86_ELAN
@@ -95,7 +73,7 @@ config X86_POWERNOW_K7_ACPI
 
 config X86_POWERNOW_K8
        tristate "AMD Opteron/Athlon64 PowerNow!"
-       depends on CPU_FREQ && EXPERIMENTAL
+       depends on CPU_FREQ_TABLE && EXPERIMENTAL
        help
          This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors.
 
@@ -122,29 +100,40 @@ config X86_GX_SUSPMOD
 config X86_SPEEDSTEP_CENTRINO
        tristate "Intel Enhanced SpeedStep"
        depends on CPU_FREQ_TABLE
+       select X86_SPEEDSTEP_CENTRINO_TABLE if (!X86_SPEEDSTEP_CENTRINO_ACPI)
        help
          This adds the CPUFreq driver for Enhanced SpeedStep enabled
-         mobile CPUs.  This means Intel Pentium M (Centrino) CPUs.
+         mobile CPUs.  This means Intel Pentium M (Centrino) CPUs. However,
+         you also need to say Y to "Use ACPI tables to decode..." below
+         [which might imply enabling ACPI] if you want to use this driver
+         on non-Banias CPUs.
          
          For details, take a look at <file:Documentation/cpu-freq/>.
          
          If in doubt, say N.
 
-config X86_SPEEDSTEP_CENTRINO_TABLE
-       bool
-       depends on X86_SPEEDSTEP_CENTRINO
-       default y
-
 config X86_SPEEDSTEP_CENTRINO_ACPI
-       bool "Use ACPI tables to decode valid frequency/voltage pairs (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       bool "Use ACPI tables to decode valid frequency/voltage pairs"
+       depends on X86_SPEEDSTEP_CENTRINO
        depends on ((X86_SPEEDSTEP_CENTRINO = "m" && ACPI_PROCESSOR) || (X86_SPEEDSTEP_CENTRINO = "y" && ACPI_PROCESSOR = "y"))
+       default y
        help
          Use primarily the information provided in the BIOS ACPI tables
-         to determine valid CPU frequency and voltage pairings.
+         to determine valid CPU frequency and voltage pairings. It is
+         required for the driver to work on non-Banias CPUs.
 
          If in doubt, say Y.
 
+config X86_SPEEDSTEP_CENTRINO_TABLE
+       bool "Built-in tables for Banias CPUs"
+       depends on X86_SPEEDSTEP_CENTRINO
+       default y
+       help
+         Use built-in tables for Banias CPUs if ACPI encoding
+         is not available.
+
+         If in doubt, say N.
+
 config X86_SPEEDSTEP_ICH
        tristate "Intel Speedstep on ICH-M chipsets (ioport interface)"
        depends on CPU_FREQ_TABLE
@@ -181,27 +170,23 @@ config X86_P4_CLOCKMOD
 
          If in doubt, say N.
 
-config X86_SPEEDSTEP_LIB
-       tristate
-       depends on (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
-       default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
-
-config X86_SPEEDSTEP_RELAXED_CAP_CHECK
-       bool "Relaxed speedstep capability checks"
-       depends on (X86_SPEEDSTEP_SMI || X86_SPEEDSTEP_ICH)
+config X86_CPUFREQ_NFORCE2
+       tristate "nVidia nForce2 FSB changing"
+       depends on CPU_FREQ && EXPERIMENTAL
        help
-         Don't perform all checks for a speedstep capable system which would 
-         normally be done. Some ancient or strange systems, though speedstep 
-         capable, don't always indicate that they are speedstep capable. This 
-         option let's the probing code bypass some of those checks if the
-         parameter "relaxed_check=1" is passed to the module.
+         This adds the CPUFreq driver for FSB changing on nVidia nForce2
+         plattforms.
+
+         For details, take a look at <file:Documentation/cpu-freq/>.
+
+         If in doubt, say N.
 
 config X86_LONGRUN
        tristate "Transmeta LongRun"
        depends on CPU_FREQ
        help
-         This adds the CPUFreq driver for Transmeta Crusoe processors which
-         support LongRun.
+         This adds the CPUFreq driver for Transmeta Crusoe and Efficeon processors
+         which support LongRun.
 
          For details, take a look at <file:Documentation/cpu-freq/>.
 
@@ -219,4 +204,34 @@ config X86_LONGHAUL
 
          If in doubt, say N.
 
+comment "shared options"
+       depends on CPU_FREQ
+
+config X86_ACPI_CPUFREQ_PROC_INTF
+        bool "/proc/acpi/processor/../performance interface (deprecated)"
+       depends on PROC_FS
+       depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K7_ACPI || X86_POWERNOW_K8_ACPI
+       help
+         This enables the deprecated /proc/acpi/processor/../performance 
+         interface. While it is helpful for debugging, the generic,
+         cross-architecture cpufreq interfaces should be used.
+
+         If in doubt, say N.
+
+config X86_SPEEDSTEP_LIB
+       tristate
+       depends on (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
+       default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
+
+config X86_SPEEDSTEP_RELAXED_CAP_CHECK
+       bool "Relaxed speedstep capability checks"
+       depends on (X86_SPEEDSTEP_SMI || X86_SPEEDSTEP_ICH)
+       help
+         Don't perform all checks for a speedstep capable system which would 
+         normally be done. Some ancient or strange systems, though speedstep 
+         capable, don't always indicate that they are speedstep capable. This 
+         option lets the probing code bypass some of those checks if the
+         parameter "relaxed_check=1" is passed to the module.
+
+
 endmenu
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);
+
index 82f7c02..a477ae1 100644 (file)
 #include <asm/msr.h>
 #include "speedstep-lib.h"
 
-
-/* DEBUG
- *   Define it if you want verbose debug output, e.g. for bug reporting
- */
-//#define SPEEDSTEP_DEBUG
-
-#ifdef SPEEDSTEP_DEBUG
-#define dprintk(msg...) printk(msg)
-#else
-#define dprintk(msg...) do { } while(0)
-#endif
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-lib", msg)
 
 #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
 static int relaxed_check = 0;
@@ -83,7 +73,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
 
        /* read MSR 0x2a - we only need the low 32 bits */
        rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
-       dprintk(KERN_DEBUG "speedstep-lib: P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+       dprintk("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
        msr_tmp = msr_lo;
 
        /* decode the FSB */
@@ -96,9 +86,10 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
        }
 
        /* decode the multiplier */
-       if (processor == SPEEDSTEP_PROCESSOR_PIII_C_EARLY)
+       if (processor == SPEEDSTEP_PROCESSOR_PIII_C_EARLY) {
+               dprintk("workaround for early PIIIs\n");
                msr_lo &= 0x03c00000;
-       else
+       else
                msr_lo &= 0x0bc00000;
        msr_lo >>= 22;
        while (msr_lo != msr_decode_mult[j].bitmap) {
@@ -107,6 +98,8 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
                j++;
        }
 
+       dprintk("speed is %u\n", (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100));
+
        return (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100);
 }
 
@@ -116,7 +109,7 @@ static unsigned int pentiumM_get_frequency(void)
        u32     msr_lo, msr_tmp;
 
        rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
-       dprintk(KERN_DEBUG "speedstep-lib: PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+       dprintk("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
 
        /* see table B-2 of 24547212.pdf */
        if (msr_lo & 0x00040000) {
@@ -125,7 +118,7 @@ static unsigned int pentiumM_get_frequency(void)
        }
 
        msr_tmp = (msr_lo >> 22) & 0x1f;
-       dprintk(KERN_DEBUG "speedstep-lib: bits 22-26 are 0x%x\n", msr_tmp);
+       dprintk("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * 100 * 1000));
 
        return (msr_tmp * 100 * 1000);
 }
@@ -139,7 +132,7 @@ static unsigned int pentium4_get_frequency(void)
 
        rdmsr(0x2c, msr_lo, msr_hi);
 
-       dprintk(KERN_DEBUG "speedstep-lib: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
+       dprintk("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
 
        /* decode the FSB: see IA-32 Intel (C) Architecture Software 
         * Developer's Manual, Volume 3: System Prgramming Guide,
@@ -169,7 +162,7 @@ static unsigned int pentium4_get_frequency(void)
        /* Multiplier. */
        mult = msr_lo >> 24;
 
-       dprintk(KERN_DEBUG "speedstep-lib: P4 - FSB %u kHz; Multiplier %u\n", fsb, mult);
+       dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult));
 
        return (fsb * mult);
 }
@@ -204,6 +197,8 @@ unsigned int speedstep_detect_processor (void)
        struct cpuinfo_x86 *c = cpu_data;
        u32                     ebx, msr_lo, msr_hi;
 
+       dprintk("x86: %x, model: %x\n", c->x86, c->x86_model);
+
        if ((c->x86_vendor != X86_VENDOR_INTEL) || 
            ((c->x86 != 6) && (c->x86 != 0xF)))
                return 0;
@@ -217,7 +212,7 @@ unsigned int speedstep_detect_processor (void)
                ebx = cpuid_ebx(0x00000001);
                ebx &= 0x000000FF;
 
-               dprintk(KERN_INFO "ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
+               dprintk("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
 
                switch (c->x86_mask) {
                case 4: 
@@ -269,6 +264,7 @@ unsigned int speedstep_detect_processor (void)
                /* cpuid_ebx(1) is 0x04 for desktop PIII, 
                                   0x06 for mobile PIII-M */
                ebx = cpuid_ebx(0x00000001);
+               dprintk("ebx is %x\n", ebx);
 
                ebx &= 0x000000FF;
 
@@ -286,7 +282,7 @@ unsigned int speedstep_detect_processor (void)
                /* all mobile PIII Coppermines have FSB 100 MHz
                 * ==> sort out a few desktop PIIIs. */
                rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
-               dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi);
+               dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi);
                msr_lo &= 0x00c0000;
                if (msr_lo != 0x0080000)
                        return 0;
@@ -298,11 +294,12 @@ unsigned int speedstep_detect_processor (void)
                 * bit 56 or 57 is set
                 */
                rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
-               dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi);
+               dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi);
                if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
-                       if (c->x86_mask == 0x01)
+                       if (c->x86_mask == 0x01) {
+                               dprintk("early PIII version\n");
                                return SPEEDSTEP_PROCESSOR_PIII_C_EARLY;
-                       else
+                       else
                                return SPEEDSTEP_PROCESSOR_PIII_C;
                }
 
@@ -329,10 +326,14 @@ unsigned int speedstep_get_freqs(unsigned int processor,
        if ((!processor) || (!low_speed) || (!high_speed) || (!set_state))
                return -EINVAL;
 
+       dprintk("trying to determine both speeds\n");
+
        /* get current speed */
        prev_speed = speedstep_get_processor_frequency(processor);
        if (!prev_speed)
                return -EIO;
+
+       dprintk("previous seped is %u\n", prev_speed);
        
        local_irq_save(flags);
 
@@ -344,6 +345,8 @@ unsigned int speedstep_get_freqs(unsigned int processor,
                goto out;
        }
 
+       dprintk("low seped is %u\n", *low_speed);
+
        /* switch to high state */
        set_state(SPEEDSTEP_HIGH);
        *high_speed = speedstep_get_processor_frequency(processor);
@@ -352,6 +355,8 @@ unsigned int speedstep_get_freqs(unsigned int processor,
                goto out;
        }
 
+       dprintk("high seped is %u\n", *high_speed);
+
        if (*low_speed == *high_speed) {
                ret = -ENODEV;
                goto out;
index 55df60a..98b85b6 100644 (file)
@@ -187,6 +187,14 @@ static void __init geode_configure(void)
 }
 
 
+#ifdef CONFIG_PCI
+static struct pci_device_id cyrix_55x0[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510) },
+       { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520) },
+       { },
+};
+#endif
+
 static void __init init_cyrix(struct cpuinfo_x86 *c)
 {
        unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
@@ -274,8 +282,7 @@ static void __init init_cyrix(struct cpuinfo_x86 *c)
                /*
                 *  The 5510/5520 companion chips have a funky PIT.
                 */  
-               if (pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
-                   pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
+               if (pci_dev_present(cyrix_55x0))
                        pit_latch_buggy = 1;
 
                /* GXm supports extended cpuid levels 'ala' AMD */
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;
+}
index 207f10d..bf6d1ae 100644 (file)
@@ -22,13 +22,13 @@ int nr_mce_banks;
 EXPORT_SYMBOL_GPL(nr_mce_banks);       /* non-fatal.o */
 
 /* Handle unconfigured int18 (should never happen) */
-static asmlinkage void unexpected_machine_check(struct pt_regs * regs, long error_code)
+static fastcall void unexpected_machine_check(struct pt_regs * regs, long error_code)
 {      
        printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
 }
 
 /* Call the installed machine check handler for this CPU setup. */
-void asmlinkage (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
+void fastcall (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
 
 /* This has to be run for each processor */
 void __init mcheck_init(struct cpuinfo_x86 *c)
index b097a7c..dc2416d 100644 (file)
@@ -7,7 +7,7 @@ void intel_p6_mcheck_init(struct cpuinfo_x86 *c);
 void winchip_mcheck_init(struct cpuinfo_x86 *c);
 
 /* Call the installed machine check handler for this CPU setup. */
-extern asmlinkage void (*machine_check_vector)(struct pt_regs *, long error_code);
+extern fastcall void (*machine_check_vector)(struct pt_regs *, long error_code);
 
 extern int mce_disabled __initdata;
 extern int nr_mce_banks;
index 959f573..f9efeeb 100644 (file)
@@ -77,22 +77,24 @@ static int have_wrcomb(void)
 {
        struct pci_dev *dev;
        
-       if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
+       if ((dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
                /* ServerWorks LE chipsets have problems with write-combining 
                   Don't allow it and leave room for other chipsets to be tagged */
                if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
                    dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) {
                        printk(KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n");
+                       pci_dev_put(dev);
                        return 0;
                }
                /* Intel 450NX errata # 23. Non ascending cachline evictions to
                   write combining memory may resulting in data corruption */
                if (dev->vendor == PCI_VENDOR_ID_INTEL &&
-                   dev->device == PCI_DEVICE_ID_INTEL_82451NX)
-               {
+                   dev->device == PCI_DEVICE_ID_INTEL_82451NX) {
                        printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n");
+                       pci_dev_put(dev);
                        return 0;
                }
+               pci_dev_put(dev);
        }               
        return (mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0);
 }
@@ -147,10 +149,8 @@ static void ipi_handler(void *info)
        local_irq_save(flags);
 
        atomic_dec(&data->count);
-       while(!atomic_read(&data->gate)) {
+       while(!atomic_read(&data->gate))
                cpu_relax();
-               barrier();
-       }
 
        /*  The master has cleared me to execute  */
        if (data->smp_reg != ~0U) 
@@ -160,10 +160,9 @@ static void ipi_handler(void *info)
                mtrr_if->set_all();
 
        atomic_dec(&data->count);
-       while(atomic_read(&data->gate)) {
+       while(atomic_read(&data->gate))
                cpu_relax();
-               barrier();
-       }
+
        atomic_dec(&data->count);
        local_irq_restore(flags);
 }
@@ -228,10 +227,9 @@ static void set_mtrr(unsigned int reg, unsigned long base,
 
        local_irq_save(flags);
 
-       while(atomic_read(&data.count)) {
+       while(atomic_read(&data.count))
                cpu_relax();
-               barrier();
-       }
+
        /* ok, reset count and toggle gate */
        atomic_set(&data.count, num_booting_cpus() - 1);
        atomic_set(&data.gate,1);
@@ -248,10 +246,9 @@ static void set_mtrr(unsigned int reg, unsigned long base,
                mtrr_if->set(reg,base,size,type);
 
        /* wait for the others */
-       while(atomic_read(&data.count)) {
+       while(atomic_read(&data.count))
                cpu_relax();
-               barrier();
-       }
+
        atomic_set(&data.count, num_booting_cpus() - 1);
        atomic_set(&data.gate,0);
 
@@ -259,10 +256,9 @@ static void set_mtrr(unsigned int reg, unsigned long base,
         * Wait here for everyone to have seen the gate change
         * So we're the last ones to touch 'data'
         */
-       while(atomic_read(&data.count)) {
+       while(atomic_read(&data.count))
                cpu_relax();
-               barrier();
-       }
+
        local_irq_restore(flags);
 }
 
index 4c44e97..30898a2 100644 (file)
@@ -32,7 +32,7 @@ static void __init init_nexgen(struct cpuinfo_x86 * c)
        c->x86_cache_size = 256; /* A few had 1 MB... */
 }
 
-static void nexgen_identify(struct cpuinfo_x86 * c)
+static void __init nexgen_identify(struct cpuinfo_x86 * c)
 {
        /* Detect NexGen with old hypercode */
        if ( deep_magic_nexgen_probe() ) {
index 4bb3c56..f57e5ee 100644 (file)
@@ -8,7 +8,7 @@ static void __init init_transmeta(struct cpuinfo_x86 *c)
 {
        unsigned int cap_mask, uk, max, dummy;
        unsigned int cms_rev1, cms_rev2;
-       unsigned int cpu_rev, cpu_freq, cpu_flags;
+       unsigned int cpu_rev, cpu_freq, cpu_flags, new_cpu_rev;
        char cpu_info[65];
 
        get_model_name(c);      /* Same as AMD/Cyrix */
@@ -16,17 +16,24 @@ static void __init init_transmeta(struct cpuinfo_x86 *c)
 
        /* Print CMS and CPU revision */
        max = cpuid_eax(0x80860000);
+       cpu_rev = 0;
        if ( max >= 0x80860001 ) {
                cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags); 
-               printk(KERN_INFO "CPU: Processor revision %u.%u.%u.%u, %u MHz\n",
-                      (cpu_rev >> 24) & 0xff,
-                      (cpu_rev >> 16) & 0xff,
-                      (cpu_rev >> 8) & 0xff,
-                      cpu_rev & 0xff,
-                      cpu_freq);
+               if (cpu_rev != 0x02000000) {
+                       printk(KERN_INFO "CPU: Processor revision %u.%u.%u.%u, %u MHz\n",
+                               (cpu_rev >> 24) & 0xff,
+                               (cpu_rev >> 16) & 0xff,
+                               (cpu_rev >> 8) & 0xff,
+                               cpu_rev & 0xff,
+                               cpu_freq);
+               }
        }
        if ( max >= 0x80860002 ) {
-               cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy);
+               cpuid(0x80860002, &new_cpu_rev, &cms_rev1, &cms_rev2, &dummy);
+               if (cpu_rev == 0x02000000) {
+                       printk(KERN_INFO "CPU: Processor revision %08X, %u MHz\n",
+                               new_cpu_rev, cpu_freq);
+               }
                printk(KERN_INFO "CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n",
                       (cms_rev1 >> 24) & 0xff,
                       (cms_rev1 >> 16) & 0xff,
index 4d066cc..b9eb1a9 100644 (file)
@@ -42,6 +42,7 @@ 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];
+void jprobe_return_end(void);
 
 /*
  * returns non-zero if opcode modifies the interrupt flag.
@@ -58,9 +59,14 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode)
        return 0;
 }
 
-void arch_prepare_kprobe(struct kprobe *p)
+int arch_prepare_kprobe(struct kprobe *p)
+{
+       memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+       return 0;
+}
+
+void arch_remove_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)
@@ -73,7 +79,7 @@ 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;
+       regs->eip = (unsigned long)&p->ainsn.insn;
 }
 
 /*
@@ -111,6 +117,11 @@ static inline int kprobe_handler(struct pt_regs *regs)
        p = get_kprobe(addr);
        if (!p) {
                unlock_kprobes();
+               if (regs->eflags & VM_MASK) {
+                       /* We are in virtual-8086 mode. Return 0 */
+                       goto no_kprobe;
+               }
+
                if (*addr != BREAKPOINT_INSTRUCTION) {
                        /*
                         * The breakpoint instruction was removed right
@@ -153,7 +164,7 @@ static inline int kprobe_handler(struct pt_regs *regs)
  * 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.
+ * 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:
@@ -173,10 +184,10 @@ 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 copy_eip = (unsigned long)&p->ainsn.insn;
        unsigned long orig_eip = (unsigned long)p->addr;
 
-       switch (p->insn[0]) {
+       switch (p->ainsn.insn[0]) {
        case 0x9c:              /* pushfl */
                *tos &= ~(TF_MASK | IF_MASK);
                *tos |= kprobe_old_eflags;
@@ -185,13 +196,13 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs)
                *tos = orig_eip + (*tos - copy_eip);
                break;
        case 0xff:
-               if ((p->insn[1] & 0x30) == 0x10) {
+               if ((p->ainsn.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 */
+               } else if (((p->ainsn.insn[1] & 0x31) == 0x20) ||       /* jmp near, absolute indirect */
+                          ((p->ainsn.insn[1] & 0x31) == 0x21)) {       /* jmp far, absolute indirect */
                        /* eip is correct. */
                        next_eip = regs->eip;
                }
@@ -315,12 +326,12 @@ void jprobe_return(void)
 {
        preempt_enable_no_resched();
        asm volatile ("       xchgl   %%ebx,%%esp     \n"
-                     "       int3                      \n"::"b"
+                     "       int3                      \n"
+                     "       .globl jprobe_return_end  \n"
+                     "       jprobe_return_end:        \n"
+                     "       nop                       \n"::"b"
                      (jprobe_saved_esp):"memory");
 }
-void jprobe_return_end(void)
-{
-};
 
 int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
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
index 073912c..be61aa8 100644 (file)
  *    we cannot lose wakeup events.
  */
 
-asmlinkage void __up(struct semaphore *sem)
+fastcall void __up(struct semaphore *sem)
 {
        wake_up(&sem->wait);
 }
 
-asmlinkage void __sched __down(struct semaphore * sem)
+fastcall void __sched __down(struct semaphore * sem)
 {
        struct task_struct *tsk = current;
        DECLARE_WAITQUEUE(wait, tsk);
@@ -91,7 +91,7 @@ asmlinkage void __sched __down(struct semaphore * sem)
        tsk->state = TASK_RUNNING;
 }
 
-asmlinkage int __sched __down_interruptible(struct semaphore * sem)
+fastcall int __sched __down_interruptible(struct semaphore * sem)
 {
        int retval = 0;
        struct task_struct *tsk = current;
@@ -154,7 +154,7 @@ asmlinkage int __sched __down_interruptible(struct semaphore * sem)
  * single "cmpxchg" without failure cases,
  * but then it wouldn't work on a 386.
  */
-asmlinkage int __down_trylock(struct semaphore * sem)
+fastcall int __down_trylock(struct semaphore * sem)
 {
        int sleepers;
        unsigned long flags;
@@ -183,9 +183,9 @@ asmlinkage int __down_trylock(struct semaphore * sem)
  * need to convert that sequence back into the C sequence when
  * there is contention on the semaphore.
  *
- * %ecx contains the semaphore pointer on entry. Save the C-clobbered
- * registers (%eax, %edx and %ecx) except %eax when used as a return
- * value..
+ * %eax contains the semaphore pointer on entry. Save the C-clobbered
+ * registers (%eax, %edx and %ecx) except %eax whish is either a return
+ * value or just clobbered..
  */
 asm(
 ".section .sched.text\n"
@@ -196,13 +196,11 @@ asm(
        "pushl %ebp\n\t"
        "movl  %esp,%ebp\n\t"
 #endif
-       "pushl %eax\n\t"
        "pushl %edx\n\t"
        "pushl %ecx\n\t"
        "call __down\n\t"
        "popl %ecx\n\t"
        "popl %edx\n\t"
-       "popl %eax\n\t"
 #if defined(CONFIG_FRAME_POINTER)
        "movl %ebp,%esp\n\t"
        "popl %ebp\n\t"
@@ -257,13 +255,11 @@ asm(
 ".align 4\n"
 ".globl __up_wakeup\n"
 "__up_wakeup:\n\t"
-       "pushl %eax\n\t"
        "pushl %edx\n\t"
        "pushl %ecx\n\t"
        "call __up\n\t"
        "popl %ecx\n\t"
        "popl %edx\n\t"
-       "popl %eax\n\t"
        "ret"
 );
 
index a9711fc..a4ec0f2 100644 (file)
@@ -319,47 +319,57 @@ unsigned long get_cmos_time(void)
        return retval;
 }
 
-static long clock_cmos_diff;
+static long clock_cmos_diff, sleep_start;
 
-static int time_suspend(struct sys_device *dev, u32 state)
+static int timer_suspend(struct sys_device *dev, u32 state)
 {
        /*
         * Estimate time zone so that set_time can update the clock
         */
        clock_cmos_diff = -get_cmos_time();
        clock_cmos_diff += get_seconds();
+       sleep_start = get_cmos_time();
        return 0;
 }
 
-static int time_resume(struct sys_device *dev)
+static int timer_resume(struct sys_device *dev)
 {
        unsigned long flags;
-       unsigned long sec = get_cmos_time() + clock_cmos_diff;
+       unsigned long sec;
+       unsigned long sleep_length;
+
+#ifdef CONFIG_HPET_TIMER
+       if (is_hpet_enabled())
+               hpet_reenable();
+#endif
+       sec = get_cmos_time() + clock_cmos_diff;
+       sleep_length = get_cmos_time() - sleep_start;
        write_seqlock_irqsave(&xtime_lock, flags);
        xtime.tv_sec = sec;
        xtime.tv_nsec = 0;
        write_sequnlock_irqrestore(&xtime_lock, flags);
+       jiffies += sleep_length * HZ;
        return 0;
 }
 
-static struct sysdev_class pit_sysclass = {
-       .resume = time_resume,
-       .suspend = time_suspend,
-       set_kset_name("pit"),
+static struct sysdev_class timer_sysclass = {
+       .resume = timer_resume,
+       .suspend = timer_suspend,
+       set_kset_name("timer"),
 };
 
 
 /* XXX this driverfs stuff should probably go elsewhere later -john */
-static struct sys_device device_i8253 = {
+static struct sys_device device_timer = {
        .id     = 0,
-       .cls    = &pit_sysclass,
+       .cls    = &timer_sysclass,
 };
 
 static int time_init_device(void)
 {
-       int error = sysdev_class_register(&pit_sysclass);
+       int error = sysdev_class_register(&timer_sysclass);
        if (!error)
-               error = sysdev_register(&device_i8253);
+               error = sysdev_register(&device_timer);
        return error;
 }
 
@@ -371,9 +381,9 @@ extern void (*late_time_init)(void);
 void __init hpet_time_init(void)
 {
        xtime.tv_sec = get_cmos_time();
-       wall_to_monotonic.tv_sec = -xtime.tv_sec;
        xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-       wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
+       set_normalized_timespec(&wall_to_monotonic,
+               -xtime.tv_sec, -xtime.tv_nsec);
 
        if (hpet_enable() >= 0) {
                printk("Using HPET for base-timer\n");
@@ -399,9 +409,9 @@ void __init time_init(void)
        }
 #endif
        xtime.tv_sec = get_cmos_time();
-       wall_to_monotonic.tv_sec = -xtime.tv_sec;
        xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-       wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
+       set_normalized_timespec(&wall_to_monotonic,
+               -xtime.tv_sec, -xtime.tv_nsec);
 
        cur_timer = select_timer();
        printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);
index 7271b06..f7f9000 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/init.h>
 #include <linux/timex.h>
 #include <linux/errno.h>
+#include <linux/jiffies.h>
 
 #include <asm/io.h>
 #include <asm/timer.h>
index 34f1f3d..f6f1206 100644 (file)
@@ -245,11 +245,15 @@ static void delay_cyclone(unsigned long loops)
 /************************************************************/
 
 /* cyclone timer_opts struct */
-struct timer_opts timer_cyclone = {
+static struct timer_opts timer_cyclone = {
        .name = "cyclone",
-       .init = init_cyclone, 
        .mark_offset = mark_offset_cyclone, 
        .get_offset = get_offset_cyclone,
        .monotonic_clock =      monotonic_clock_cyclone,
        .delay = delay_cyclone,
 };
+
+struct init_timer_opts __initdata timer_cyclone_init = {
+       .init = init_cyclone,
+       .opts = &timer_cyclone,
+};
index 15035a5..56d8fc1 100644 (file)
@@ -177,11 +177,15 @@ static int __init init_hpet(char* override)
 /************************************************************/
 
 /* tsc timer_opts struct */
-struct timer_opts timer_hpet = {
+static struct timer_opts timer_hpet = {
        .name =                 "hpet",
-       .init =                 init_hpet,
        .mark_offset =          mark_offset_hpet,
        .get_offset =           get_offset_hpet,
        .monotonic_clock =      monotonic_clock_hpet,
        .delay =                delay_hpet,
 };
+
+struct init_timer_opts __initdata timer_hpet_init = {
+       .init = init_hpet,
+       .opts = &timer_hpet,
+};
index a433cb0..967d545 100644 (file)
@@ -152,14 +152,18 @@ static unsigned long get_offset_pit(void)
 
 /* tsc timer_opts struct */
 struct timer_opts timer_pit = {
-       .name =         "pit",
-       .init =         init_pit, 
-       .mark_offset =  mark_offset_pit, 
-       .get_offset =   get_offset_pit,
+       .name = "pit",
+       .mark_offset = mark_offset_pit, 
+       .get_offset = get_offset_pit,
        .monotonic_clock = monotonic_clock_pit,
        .delay = delay_pit,
 };
 
+struct init_timer_opts __initdata timer_pit_init = {
+       .init = init_pit, 
+       .opts = &timer_pit,
+};
+
 void setup_pit_timer(void)
 {
        extern spinlock_t i8253_lock;
@@ -181,7 +185,7 @@ static int timer_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class timer_sysclass = {
-       set_kset_name("timer"),
+       set_kset_name("timer_pit"),
        .resume = timer_resume,
 };
 
index ffd4869..ab43394 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
-int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
        int counter;
        int newcount;
index 1d1954a..9707a9e 100644 (file)
@@ -52,72 +52,27 @@ int                         mip_port;
 unsigned long          mip_addr, host_addr;
 
 #if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_ACPI_BOOT))
-static unsigned long cycle_irqs = 0;
-static unsigned long free_irqs = 0;
-static int gsi_map[MAX_GSI_MAPSIZE] = { [0 ... MAX_GSI_MAPSIZE-1] = -1 };
 
 /*
  * GSI override for ES7000 platforms.
  */
 
-static int __init
-es7000_gsi_override(int ioapic, int gsi)
-{
-       static int newgsi = 0;
-
-       if (gsi_map[gsi] != -1)
-               gsi = gsi_map[gsi];
-       else if (cycle_irqs ^ free_irqs) {
-               newgsi = find_next_bit(&cycle_irqs, IOAPIC_GSI_BOUND(0), newgsi);
-               __set_bit(newgsi, &free_irqs);
-               gsi_map[gsi] = newgsi;
-               gsi = newgsi;
-               newgsi++;
-               Dprintk("es7000_gsi_override: free_irqs = 0x%lx\n", free_irqs);
-       }
+static unsigned int base;
 
-       return gsi;
-}
-
-static int __init
+static int
 es7000_rename_gsi(int ioapic, int gsi)
 {
-       static int initialized = 0;
-       int i;
-
-       /*
-        * These should NEVER be true at this point but we'd rather be
-        * safe than sorry.
-        */
-       if (acpi_disabled || acpi_pci_disabled || acpi_noirq)
-               return gsi;
-
-       if (ioapic)
-               return gsi;
-
-       if (!initialized) {
-               unsigned long tmp_irqs = 0;
-
-               for (i = 0; i < nr_ioapic_registers[0]; i++)
-                       __set_bit(mp_irqs[i].mpc_srcbusirq, &tmp_irqs);
-
-               cycle_irqs = (~tmp_irqs & io_apic_irqs & ((1 << IOAPIC_GSI_BOUND(0)) - 1));
-
-               initialized = 1;
-               Dprintk("es7000_rename_gsi: cycle_irqs = 0x%lx\n", cycle_irqs);
-       }
-
-       for (i = 0; i < nr_ioapic_registers[0]; i++) {
-               if (mp_irqs[i].mpc_srcbusirq == gsi) {
-                       if (mp_irqs[i].mpc_dstirq == gsi)
-                               return gsi;
-                       else
-                               return es7000_gsi_override(0, gsi);
-               }
+       if (!base) {
+               int i;
+               for (i = 0; i < nr_ioapics; i++)
+                       base += nr_ioapic_registers[i];
        }
 
+       if (!ioapic && (gsi < 16)) 
+               gsi += base;
        return gsi;
 }
+
 #endif // (CONFIG_X86_IO_APIC) && (CONFIG_ACPI_INTERPRETER || CONFIG_ACPI_BOOT)
 
 /*
@@ -184,7 +139,7 @@ parse_unisys_oem (char *oemptr, int oem_entries)
        } else {
                printk("\nEnabling ES7000 specific features...\n");
                es7000_plat = 1;
-               platform_rename_gsi = es7000_rename_gsi;
+               ioapic_renumber_irq = es7000_rename_gsi;
        }
        return es7000_plat;
 }
index a6270ee..c5e0d01 100644 (file)
@@ -37,7 +37,7 @@
 
 static inline unsigned long mmap_base(struct mm_struct *mm)
 {
-       unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur;
+       unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
 
        if (gap < MIN_GAP)
                gap = MIN_GAP;
@@ -59,7 +59,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
         */
        if (sysctl_legacy_va_layout ||
                        (current->personality & ADDR_COMPAT_LAYOUT) ||
-                       current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) {
+                       current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) {
                mm->mmap_base = TASK_UNMAPPED_BASE;
                mm->get_unmapped_area = arch_get_unmapped_area;
                mm->unmap_area = arch_unmap_area;
index 88c832a..4008b6c 100644 (file)
@@ -23,6 +23,7 @@ extern  void pcibios_sort(void);
 unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
                                PCI_PROBE_MMCONF;
 
+int pci_routeirq;
 int pcibios_last_bus = -1;
 struct pci_bus *pci_root_bus = NULL;
 struct pci_raw_ops *raw_pci_ops;
@@ -227,6 +228,9 @@ char * __devinit  pcibios_setup(char *str)
        } else if (!strcmp(str, "assign-busses")) {
                pci_probe |= PCI_ASSIGN_ALL_BUSSES;
                return NULL;
+       } else if (!strcmp(str, "routeirq")) {
+               pci_routeirq = 1;
+               return NULL;
        }
        return str;
 }
index ec859ad..7a7b35a 100644 (file)
@@ -96,15 +96,13 @@ pcibios_align_resource(void *data, struct resource *res,
 
 static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
 {
-       struct list_head *ln;
        struct pci_bus *bus;
        struct pci_dev *dev;
        int idx;
        struct resource *r, *pr;
 
        /* Depth-First Search on bus tree */
-       for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
-               bus = pci_bus_b(ln);
+       list_for_each_entry(bus, bus_list, node) {
                if ((dev = bus->self)) {
                        for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
                                r = &dev->resource[idx];
@@ -126,7 +124,7 @@ static void __init pcibios_allocate_resources(int pass)
        u16 command;
        struct resource *r, *pr;
 
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
                pci_read_config_word(dev, PCI_COMMAND, &command);
                for(idx = 0; idx < 6; idx++) {
                        r = &dev->resource[idx];
@@ -170,7 +168,7 @@ static int __init pcibios_assign_resources(void)
        int idx;
        struct resource *r;
 
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
                int class = dev->class >> 8;
 
                /* Don't touch classless devices and host bridges */
@@ -297,7 +295,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        /* Write-combine setting is ignored, it is changed via the mtrr
         * interfaces on this platform.
         */
-       if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+       if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                             vma->vm_end - vma->vm_start,
                             vma->vm_page_prot))
                return -EAGAIN;
index f16fd2e..74756c0 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.9-rc2
-# Tue Sep 28 13:26:53 2004
+# Linux kernel version: 2.6.10-rc2
+# Mon Nov 29 13:27:48 2004
 #
 
 #
@@ -9,6 +9,7 @@
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
@@ -22,6 +23,7 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
@@ -29,12 +31,12 @@ 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
 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
 
 #
@@ -45,6 +47,7 @@ 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
 CONFIG_STOP_MACHINE=y
 
@@ -84,6 +87,7 @@ CONFIG_PREEMPT=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_IA32_SUPPORT=y
 CONFIG_COMPAT=y
+# CONFIG_IA64_MCA_RECOVERY is not set
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
 
@@ -107,9 +111,11 @@ CONFIG_ACPI=y
 CONFIG_ACPI_BOOT=y
 CONFIG_ACPI_INTERPRETER=y
 CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_VIDEO=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_THERMAL=m
+CONFIG_ACPI_BLACKLIST_YEAR=0
 # CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_BUS=y
 CONFIG_ACPI_POWER=y
@@ -131,9 +137,13 @@ CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG_PCI is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
 #
-# CONFIG_PCMCIA is not set
 
 #
 # Device Drivers
@@ -160,6 +170,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Plug and Play support
 #
+# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -175,6 +186,16 @@ CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=m
 CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -193,7 +214,6 @@ CONFIG_BLK_DEV_IDECD=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
@@ -282,12 +302,14 @@ CONFIG_SCSI_SPI_ATTRS=m
 # 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=y
+# CONFIG_SCSI_QLOGIC_1280_1040 is not set
 CONFIG_SCSI_QLA2XXX=y
 # CONFIG_SCSI_QLA21XX is not set
 # CONFIG_SCSI_QLA22XX is not set
@@ -311,6 +333,7 @@ CONFIG_MD_RAID10=m
 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
@@ -357,6 +380,8 @@ CONFIG_INET=y
 # 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
 
@@ -376,7 +401,6 @@ CONFIG_INET=y
 # 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
@@ -437,7 +461,6 @@ CONFIG_EEPRO100=y
 # 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)
@@ -450,6 +473,7 @@ CONFIG_EEPRO100=y
 # 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
 
 #
@@ -549,7 +573,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_ACPI is not set
+CONFIG_SERIAL_8250_ACPI=y
 CONFIG_SERIAL_8250_NR_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -627,6 +651,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
@@ -644,14 +669,17 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_SENSORS_FSCHER is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 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_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -773,7 +801,7 @@ CONFIG_SND_CS4281=m
 # CONFIG_SND_VX222 is not set
 
 #
-# ALSA USB devices
+# USB devices
 #
 # CONFIG_SND_USB_AUDIO is not set
 # CONFIG_SND_USB_USX2Y is not set
@@ -797,6 +825,8 @@ CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
 # USB Host Controller Drivers
@@ -826,7 +856,7 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
 CONFIG_USB_HID=m
 CONFIG_USB_HIDINPUT=y
@@ -864,7 +894,7 @@ CONFIG_USB_HIDDEV=y
 #
 
 #
-# USB Network adaptors
+# USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_KAWETH is not set
@@ -893,9 +923,14 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
 # CONFIG_USB_TEST is not set
 
+#
+# USB ATM/DSL drivers
+#
+
 #
 # USB Gadget Support
 #
@@ -925,6 +960,7 @@ CONFIG_XFS_POSIX_ACL=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
 CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 
@@ -957,6 +993,7 @@ CONFIG_SYSFS=y
 CONFIG_DEVPTS_FS_XATTR=y
 CONFIG_DEVPTS_FS_SECURITY=y
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -1087,9 +1124,11 @@ CONFIG_OPROFILE=y
 #
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_IA64_GRANULE_16MB is not set
 CONFIG_IA64_GRANULE_64MB=y
@@ -1102,6 +1141,7 @@ CONFIG_SYSVIPC_COMPAT=y
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -1115,7 +1155,7 @@ 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_WP512 is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
@@ -1126,6 +1166,7 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_TEA is not set
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
index ce94125..2af0174 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.9-rc2
-# Tue Sep 28 09:03:25 2004
+# Linux kernel version: 2.6.10-rc1
+# Tue Nov  2 11:35:10 2004
 #
 
 #
@@ -9,6 +9,7 @@
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
@@ -22,6 +23,7 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=20
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_EMBEDDED is not set
@@ -30,12 +32,12 @@ 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_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
 
 #
@@ -46,6 +48,7 @@ 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
 CONFIG_STOP_MACHINE=y
 
@@ -83,6 +86,7 @@ CONFIG_HOTPLUG_CPU=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_IA32_SUPPORT=y
 CONFIG_COMPAT=y
+CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
 
@@ -109,6 +113,7 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_THERMAL=m
+CONFIG_ACPI_BLACKLIST_YEAR=0
 # CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_BUS=y
 CONFIG_ACPI_POWER=y
@@ -136,9 +141,13 @@ CONFIG_HOTPLUG_PCI_ACPI=m
 # CONFIG_HOTPLUG_PCI_SHPC is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
 #
-# CONFIG_PCMCIA is not set
 
 #
 # Device Drivers
@@ -180,6 +189,16 @@ CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=m
 CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -198,7 +217,6 @@ CONFIG_BLK_DEV_IDECD=y
 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
@@ -288,6 +306,7 @@ CONFIG_SCSI_FC_ATTRS=y
 # 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=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
@@ -299,6 +318,7 @@ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 CONFIG_SCSI_QLOGIC_FC=y
 # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
 CONFIG_SCSI_QLOGIC_1280=y
+# CONFIG_SCSI_QLOGIC_1280_1040 is not set
 CONFIG_SCSI_QLA2XXX=y
 CONFIG_SCSI_QLA21XX=m
 CONFIG_SCSI_QLA22XX=m
@@ -371,6 +391,7 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -390,7 +411,6 @@ CONFIG_SYN_COOKIES=y
 # 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
@@ -463,7 +483,6 @@ CONFIG_E100=m
 # 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)
@@ -477,6 +496,7 @@ CONFIG_E1000=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 
 #
@@ -691,6 +711,8 @@ CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
 # USB Host Controller Drivers
@@ -720,7 +742,7 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
@@ -781,9 +803,14 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
 # CONFIG_USB_TEST is not set
 
+#
+# USB ATM/DSL drivers
+#
+
 #
 # USB Gadget Support
 #
@@ -819,6 +846,7 @@ CONFIG_XFS_FS=y
 # 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=y
 
@@ -852,6 +880,8 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_TMPFS_SECURITY=y
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -983,9 +1013,11 @@ CONFIG_CRC32=y
 #
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 CONFIG_IA64_GRANULE_16MB=y
 # CONFIG_IA64_GRANULE_64MB is not set
@@ -998,6 +1030,7 @@ CONFIG_SYSVIPC_COMPAT=y
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -1011,7 +1044,7 @@ 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_WP512 is not set
 CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
index 3c9c307..45d69f4 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/notifier.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 
index af4b714..786e707 100644 (file)
@@ -301,7 +301,7 @@ static void rs_flush_chars(struct tty_struct *tty)
 }
 
 
-static int rs_write(struct tty_struct * tty, int from_user,
+static int rs_write(struct tty_struct * tty,
                    const unsigned char *buf, int count)
 {
        int     c, ret = 0;
@@ -310,58 +310,22 @@ static int rs_write(struct tty_struct * tty, int from_user,
 
        if (!tty || !info->xmit.buf || !tmp_buf) return 0;
 
-       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;
-                       }
-
-                       local_irq_save(flags);
-                       {
-                               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));
-                       }
-                       local_irq_restore(flags);
-
-                       buf += c;
-                       count -= c;
-                       ret += c;
-               }
-               up(&tmp_buf_sem);
-       } else {
-               local_irq_save(flags);
-               while (1) {
-                       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;
+       local_irq_save(flags);
+       while (1) {
+               c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+               if (count < c)
+                       c = count;
+               if (c <= 0) {
+                       break;
                }
-               local_irq_restore(flags);
+               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;
        }
+       local_irq_restore(flags);
        /*
         * Hey, we transmit directly from here in our case
         */
index b68534d..31fbbcd 100644 (file)
@@ -9,6 +9,7 @@
 #define _ELFCORE32_H_
 
 #include <asm/intrinsics.h>
+#include <asm/uaccess.h>
 
 #define USE_ELF_CORE_DUMP 1
 
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
+}
+
index b5026aa..3cef534 100644 (file)
@@ -868,7 +868,7 @@ end_os_mca_restore:
 
 
 GLOBAL_ENTRY(ia64_monarch_init_handler)
-
+       .prologue
        // stash the information the SAL passed to os
        SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
        ;;
@@ -907,6 +907,7 @@ IVirtual_Switch:
        adds out0=16,sp                         // out0 = pointer to pt_regs
        ;;
        DO_SAVE_SWITCH_STACK
+       .body
        adds out1=16,sp                         // out0 = pointer to switch_stack
 
        br.call.sptk.many rp=ia64_init_handler
index 88d8b21..73d6773 100644 (file)
@@ -138,7 +138,7 @@ ia64_brk (unsigned long brk)
                goto out;
 
        /* Check against rlimit.. */
-       rlim = current->rlim[RLIMIT_DATA].rlim_cur;
+       rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
        if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim)
                goto out;
 
index 1c6ee49..d509e20 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/types.h>
 #include <asm/intrinsics.h>
 #include <linux/module.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 
 /*
  * Find next zero bit in a bitmap reasonably efficiently..
index 46bdc04..c7ce92f 100644 (file)
@@ -19,7 +19,7 @@
  * acquiring the spinlock first.
  */
 int
-atomic_dec_and_lock (atomic_t *refcount, spinlock_t *lock)
+_atomic_dec_and_lock (atomic_t *refcount, spinlock_t *lock)
 {
        int old, new;
 
@@ -39,4 +39,4 @@ atomic_dec_and_lock (atomic_t *refcount, spinlock_t *lock)
        return 0;
 }
 
-EXPORT_SYMBOL(atomic_dec_and_lock);
+EXPORT_SYMBOL(_atomic_dec_and_lock);
index 2bc5be8..5b48cc5 100644 (file)
@@ -73,6 +73,7 @@ EXPORT_SYMBOL(__ia64_memset_c_io);
 #undef __ia64_writew
 #undef __ia64_writel
 #undef __ia64_writeq
+#undef __ia64_mmiowb
 
 unsigned int
 __ia64_inb (unsigned long port)
@@ -158,4 +159,10 @@ __ia64_readq_relaxed (void __iomem *addr)
        return ___ia64_readq (addr);
 }
 
+void
+__ia64_mmiowb(void)
+{
+       ___ia64_mmiowb();
+}
+
 #endif /* CONFIG_IA64_GENERIC */
index 9d4486f..b7467a9 100644 (file)
@@ -305,8 +305,15 @@ swiotlb_alloc_coherent (struct device *hwdev, size_t size, dma_addr_t *dma_handl
        flags |= GFP_DMA;
 
        ret = (void *)__get_free_pages(flags, get_order(size));
-       if (!ret)
-               return NULL;
+       if (!ret) {
+                /* DMA_FROM_DEVICE is to avoid the memcpy in map_single */
+               dma_addr_t handle;
+               handle = swiotlb_map_single(NULL, NULL, size, DMA_FROM_DEVICE);
+               if (dma_mapping_error(handle))
+                       return NULL;
+
+               ret = phys_to_virt(handle);
+       }
 
        memset(ret, 0, size);
        dev_addr = virt_to_phys(ret);
@@ -319,7 +326,12 @@ swiotlb_alloc_coherent (struct device *hwdev, size_t size, dma_addr_t *dma_handl
 void
 swiotlb_free_coherent (struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
 {
-       free_pages((unsigned long) vaddr, get_order(size));
+       if (!(vaddr >= (void *)io_tlb_start
+                    && vaddr < (void *)io_tlb_end))
+               free_pages((unsigned long) vaddr, get_order(size));
+       else
+               /* DMA_TO_DEVICE to avoid memcpy in unmap_single */
+               swiotlb_unmap_single (hwdev, dma_handle, size, DMA_TO_DEVICE);
 }
 
 static void swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
index ef2dbcf..9e5eee1 100644 (file)
@@ -70,7 +70,7 @@ static int __init topology_init(void)
        memset(sysfs_cpus, 0, sizeof(struct cpu) * NR_CPUS);
 
        for (i = 0; i < numnodes; i++)
-               if ((err = register_node(&sysfs_nodes[i], i, 0)))
+               if ((err = register_node(&sysfs_nodes[i], i, NULL)))
                        goto out;
 
        for (i = 0; i < NR_CPUS; i++)
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);
index 8a810d3..21c08ea 100644 (file)
 #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>
+#include <asm/sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/module.h>
+#include <asm/sn/geo.h>
+#include <asm/sn/sn2/sn_hwperf.h>
 
 static void *sn_hwperf_salheap = NULL;
 static int sn_hwperf_obj_cnt = 0;
@@ -80,21 +83,26 @@ out:
 static int sn_hwperf_geoid_to_cnode(char *location)
 {
        int cnode;
-       int mod, slot, slab;
-       int cmod, cslot, cslab;
+       geoid_t geoid;
+       moduleid_t module_id;
+       char type;
+       int rack, slot, slab;
+       int this_rack, this_slot, this_slab;
 
-       if (sscanf(location, "%03dc%02d#%d", &mod, &slot, &slab) != 3)
+       if (sscanf(location, "%03d%c%02d#%d", &rack, &type, &slot, &slab) != 4)
                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;
-               }
+
+       for (cnode = 0; cnode < numionodes; cnode++) {
+               geoid = cnodeid_get_geoid(cnode);
+               module_id = geo_module(geoid);
+               this_rack = MODULE_GET_RACK(module_id);
+               this_slot = MODULE_GET_BPOS(module_id);
+               this_slab = geo_slab(geoid);
+               if (rack == this_rack && slot == this_slot && slab == this_slab)
+                       break;
        }
 
-       return cnode < numnodes ? cnode : -1;
+       return cnode < numionodes ? cnode : -1;
 }
 
 static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj)
@@ -113,52 +121,35 @@ static int sn_hwperf_generic_ordinal(struct sn_hwperf_object_info *obj,
        for (ordinal=0, p=objs; p != obj; p++) {
                if (SN_HWPERF_FOREIGN(p))
                        continue;
-               if (p->location[3] == obj->location[3])
+               if (SN_HWPERF_SAME_OBJTYPE(p, obj))
                        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 *slabname_node =     "node"; /* SHub asic */
+static const char *slabname_ionode =   "ionode"; /* TIO asic */
+static const char *slabname_router =   "router"; /* NL3R or NL4R */
+static const char *slabname_other =    "other"; /* unknown asic */
 
-static const char *sn_hwperf_get_brickname(struct sn_hwperf_object_info *obj,
-                               struct sn_hwperf_object_info *objs, int *ordinal)
+static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj,
+                       struct sn_hwperf_object_info *objs, int *ordinal)
 {
-       int i;
-       const char *objtype = NULL;
+       int isnode;
+       const char *slabname = slabname_other;
 
-       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 ((isnode = SN_HWPERF_IS_NODE(obj)) || SN_HWPERF_IS_IONODE(obj)) {
+               slabname = isnode ? slabname_node : slabname_ionode;
+               *ordinal = sn_hwperf_obj_to_cnode(obj);
        }
-
-       if (i == MAX_BRICK_TYPES) {
-               objtype = "other";
+       else {
                *ordinal = sn_hwperf_generic_ordinal(obj, objs);
+               if (SN_HWPERF_IS_ROUTER(obj))
+                       slabname = slabname_router;
        }
 
-       return objtype;
+       return slabname;
 }
 
 static int sn_topology_show(struct seq_file *s, void *d)
@@ -168,7 +159,7 @@ static int sn_topology_show(struct seq_file *s, void *d)
        int e;
        int i;
        int j;
-       const char *brickname;
+       const char *slabname;
        int ordinal;
        cpumask_t cpumask;
        char slice;
@@ -194,22 +185,22 @@ static int sn_topology_show(struct seq_file *s, void *d)
                        obj->name[i] = '_';
        }
 
-       brickname = sn_hwperf_get_brickname(obj, objs, &ordinal);
-       seq_printf(s, "%s %d %s %s asic %s", brickname, ordinal, obj->location,
+       slabname = sn_hwperf_get_slabname(obj, objs, &ordinal);
+       seq_printf(s, "%s %d %s %s asic %s", slabname, ordinal, obj->location,
                obj->sn_hwp_this_part ? "local" : "shared", obj->name);
 
-       if (obj->location[3] != 'c')
+       if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
                seq_putc(s, '\n');
        else {
                seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal));
-               for (i=0; i < numnodes; i++) {
+               for (i=0; i < numionodes; i++) {
                        seq_printf(s, i ? ":%d" : ", dist %d",
                                node_distance(ordinal, i));
                }
                seq_putc(s, '\n');
 
                /*
-                * CPUs on this node
+                * CPUs on this node, if any
                 */
                cpumask = node_to_cpumask(ordinal);
                for_each_online_cpu(i) {
@@ -253,11 +244,16 @@ static int sn_topology_show(struct seq_file *s, void *d)
                                        break;
                                }
                        }
-                       if (i >= sn_hwperf_obj_cnt)
-                               continue;
                        seq_printf(s, "numalink %d %s-%d",
                            ordinal+pt, obj->location, ptdata[pt].port);
 
+                       if (i >= sn_hwperf_obj_cnt) {
+                               /* no connection */
+                               seq_puts(s, " local endpoint disconnected"
+                                           ", protocol unknown\n");
+                               continue;
+                       }
+
                        if (obj->sn_hwp_this_part && p->sn_hwp_this_part)
                                /* both ends local to this partition */
                                seq_puts(s, " local");
@@ -276,9 +272,8 @@ static int sn_topology_show(struct seq_file *s, void *d)
                         */
                        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");
+                               (SN_HWPERF_IS_NL3ROUTER(obj) ||
+                               SN_HWPERF_IS_NL3ROUTER(p)) ?  "LLP3" : "LLP4");
                }
                vfree(ptdata);
        }
@@ -405,7 +400,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
                r = -EINVAL;
                goto error;
        }
-       r = copy_from_user(&a, (const void *)arg,
+       r = copy_from_user(&a, (const void __user *)arg,
                sizeof(struct sn_hwperf_ioctl_args));
        if (r != 0) {
                r = -EFAULT;
@@ -426,7 +421,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
        }
 
        if (op & SN_HWPERF_OP_MEM_COPYIN) {
-               r = copy_from_user(p, (const void *)a.ptr, a.sz);
+               r = copy_from_user(p, (const void __user *)a.ptr, a.sz);
                if (r != 0) {
                        r = -EFAULT;
                        goto error;
@@ -473,7 +468,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
 
        case SN_HWPERF_GET_NODE_NASID:
                if (a.sz != sizeof(u64) ||
-                  (node = a.arg) < 0 || node >= numnodes) {
+                  (node = a.arg) < 0 || node >= numionodes) {
                        r = -EINVAL;
                        goto error;
                }
@@ -526,7 +521,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
        }
 
        if (op & SN_HWPERF_OP_MEM_COPYOUT) {
-               r = copy_to_user((void *)a.ptr, p, a.sz);
+               r = copy_to_user((void __user *)a.ptr, p, a.sz);
                if (r != 0) {
                        r = -EFAULT;
                        goto error;
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);
+       }
+}
index bacc0b2..65d1194 100644 (file)
@@ -3,7 +3,7 @@
 # see Documentation/kbuild/kconfig-language.txt.
 #
 
-mainmenu "Linux Kernel Configuration"
+mainmenu "Linux/M32R Kernel Configuration"
 
 config M32R
        bool
@@ -20,6 +20,10 @@ config GENERIC_ISA_DMA
        bool
        default y
 
+#config GENERIC_HARDIRQS
+#      bool
+#      default y
+
 source "init/Kconfig"
 
 
@@ -189,6 +193,10 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default n
 
+config GENERIC_CALIBRATE_DELAY
+       bool
+       default y
+
 config PREEMPT
        bool "Preemptible Kernel"
        help
@@ -346,96 +354,10 @@ 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 "arch/m32r/Kconfig.debug"
 
 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
index 63ea62a..dd4418d 100644 (file)
@@ -5,7 +5,6 @@
 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
@@ -42,6 +41,8 @@ boot := arch/m32r/boot
 
 .PHONY: zImage
 
+all: zImage
+
 zImage: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
@@ -51,5 +52,5 @@ archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
 
 define archhelp
-       @echo '  zImage                 - Compressed kernel image (arch/m32r/boot/zImage)'
+       echo  '* zImage          - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
 endef
index a8f130d..994c9aa 100644 (file)
@@ -5,10 +5,10 @@
 #
 
 targets                := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o \
-                  m32r-sio.o piggy.o vmlinux.lds
+                  piggy.o vmlinux.lds
 EXTRA_AFLAGS   := -traditional
 
-OBJECTS = $(obj)/head.o $(obj)/misc.o $(obj)/m32r_sio.o
+OBJECTS = $(obj)/head.o $(obj)/misc.o
 
 #
 # IMAGE_OFFSET is the load offset of the compression loader
@@ -28,8 +28,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
 $(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 $< >$@
+CFLAGS_misc.o += -fpic
 
 LDFLAGS_piggy.o := -r --format binary --oformat elf32-m32r-linux -T
 OBJCOPYFLAGS += -R .empty_zero_page
index 28de481..10b928e 100644 (file)
 #include <asm/page.h>
 #include <asm/assembler.h>
 
+       /*
+        * This code can be loaded anywhere, as long as output will not
+        * overlap it.
+        *
+        * NOTE: This head.S should *NOT* be compiled with -fpic.
+        *
+        */
+
        .global startup
+       .global __bss_start, _ebss, end, zimage_data, zimage_len
        __ALIGN
 startup:
        ldi     r0, #0x0000                     /* SPI, disable EI */
        mvtc    r0, psw
 
+       ldi     r12, #-8
+       bl      1f
+       .fillinsn
+1:
+       seth    r1, #high(CONFIG_MEMORY_START + 0x00400000) /* Start address */
+       add     r12, r14                                /* Real address */
+       sub     r12, r1                                 /* difference */
+
+       .global got_len
+       seth    r3, #high(_GLOBAL_OFFSET_TABLE_+8)
+       or3     r3, r3, #low(_GLOBAL_OFFSET_TABLE_+12)
+       add     r3, r14
+
+       /* Update the contents of global offset table */
+       ldi     r1, #low(got_len)
+       srli    r1, #2
+       beqz    r1, 2f
+       .fillinsn
+1:
+       ld      r2, @r3
+       add     r2, r12
+       st      r2, @r3
+       addi    r3, #4
+       addi    r1, #-1
+       bnez    r1, 1b
+       .fillinsn
+2:
+       /* XXX: resolve plt */
+
 /*
  * Clear BSS first so that there are no surprises...
  */
 #ifdef CONFIG_ISA_DUAL_ISSUE
+       seth    r2, #high(__bss_start)
+       or3     r2, r2, #low(__bss_start)
+       add     r2, r12
+       seth    r3, #high(_ebss)
+       or3     r3, r3, #low(_ebss)
+       add     r3, r12
+       sub     r3, r2
 
-       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
@@ -52,10 +94,13 @@ startup:
 .Lendloop2:
 
 #else /* not CONFIG_ISA_DUAL_ISSUE */
-
-       LDIMM   (r2, __bss_start)
-       LDIMM   (r3, _end)
-       sub     r3, r2          ; BSS size in bytes
+       seth    r2, #high(__bss_start)
+       or3     r2, r2, #low(__bss_start)
+       add     r2, r12
+       seth    r3, #high(_ebss)
+       or3     r3, r3, #low(_ebss)
+       add     r3, r12
+       sub     r3, r2
        mv      r4, r3
        srli    r4, #2          ; R4 = BSS size in longwords (rounded down)
        ldi     r1, #0          ; clear R1 for longwords store
@@ -66,27 +111,29 @@ startup:
        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 */
+       seth    r1, #high(end)
+       or3     r1, r1, #low(end)
+       add     r1, r12
+       mv      sp, r1
 
 /*
  * decompress the kernel
  */
+       mv      r0, sp
+       srli    r0, 31                          /* MMU is ON or OFF */
+        seth   r1, #high(zimage_data)
+        or3    r1, r1, #low(zimage_data)
+       add     r1, r12
+        seth   r2, #high(zimage_len)
+        or3    r2, r2, #low(zimage_len)
+       mv      r3, sp
+
        bl      decompress_kernel
 
-#if defined(CONFIG_CHIP_M32700)
+#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_OPSP) || defined(CONFIG_CHIP_VDEC2)
        /* Cache flush */
        ldi     r0, -1
        ldi     r1, 0xd0        ; invalidate i-cache, copy back d-cache
@@ -94,9 +141,14 @@ startup:
 #else
 #error "put your cache flush function, please"
 #endif
-        seth   r0, #high(CONFIG_MEMORY_START)
-        or3    r0, r0, #0x2000
-        jmp    r0
+
+       mv      r0, sp
+       srli    r0, 31                          /* MMU is ON or OFF */
+       slli    r0, 31
+       or3     r0, r0, #0x2000
+       seth    r1, #high(CONFIG_MEMORY_START)
+       or      r0, r1
+       jmp     r0
 
        .balign 512
 fake_headers_as_bzImage:
index 469c4dc..bdfd1c2 100644 (file)
@@ -6,12 +6,10 @@
  */
 
 #include <linux/config.h>
-#include <asm/m32r.h>
-#include <asm/io.h>
 
-void putc(char c);
+static void putc(char c);
 
-int puts(const char *s)
+static int puts(const char *s)
 {
        char c;
        while ((c = *s++)) putc(c);
@@ -19,6 +17,9 @@ int puts(const char *s)
 }
 
 #if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT)
+#include <asm/m32r.h>
+#include <asm/io.h>
+
 #define USE_FPGA_MAP   0
 
 #if USE_FPGA_MAP
@@ -35,7 +36,7 @@ int puts(const char *s)
 #define BOOT_SIO0TXB   PLD_ESIO0TXB
 #endif
 
-void putc(char c)
+static void putc(char c)
 {
 
        while ((*BOOT_SIO0STS & 0x3) != 0x3) ;
@@ -46,8 +47,17 @@ void putc(char c)
        *BOOT_SIO0TXB = c;
 }
 #else
-void putc(char c)
+#define SIO0STS        (volatile unsigned short *)(0xa0efd000 + 14)
+#define SIO0TXB        (volatile unsigned short *)(0xa0efd000 + 30)
+
+static void putc(char c)
 {
-       /* do nothing */
+
+       while ((*SIO0STS & 0x1) == 0) ;
+       if (c == '\n') {
+               *SIO0TXB = '\r';
+               while ((*SIO0STS & 0x1) == 0) ;
+       }
+       *SIO0TXB = c;
 }
 #endif
index 4661d38..70fa799 100644 (file)
@@ -8,8 +8,6 @@
  *
  * 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.
  */
@@ -38,9 +36,9 @@ typedef unsigned long  ulg;
 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 */
+static unsigned insize = 0;  /* valid bytes in inbuf */
+static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0;  /* bytes in output buffer */
 
 /* gzip flag byte */
 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
@@ -76,24 +74,18 @@ static void error(char *m);
 static void gzip_mark(void **);
 static void gzip_release(void **);
 
-extern char input_data[];
-extern int input_len;
+static unsigned char *input_data;
+static int input_len;
 
-static long bytes_out;
+static long bytes_out = 0;
 static uch *output_data;
-static unsigned long output_ptr;
+static unsigned long output_ptr = 0;
 
+#include "m32r_sio.c"
 
 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;
 
@@ -105,8 +97,8 @@ static void *malloc(int size)
 {
        void *p;
 
-       if (size <0) error("Malloc error\n");
-       if (free_mem_ptr == 0) error("Memory error\n");
+       if (size <0) error("Malloc error");
+       if (free_mem_ptr == 0) error("Memory error");
 
        free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
 
@@ -114,7 +106,7 @@ static void *malloc(int size)
        free_mem_ptr += size;
 
        if (free_mem_ptr >= free_mem_end_ptr)
-               error("\nOut of memory\n");
+               error("Out of memory");
 
        return p;
 }
@@ -159,7 +151,7 @@ void* memcpy(void* __dest, __const void* __src,
 static int fill_inbuf(void)
 {
        if (insize != 0) {
-               error("ran out of input data\n");
+               error("ran out of input data");
        }
 
        inbuf = input_data;
@@ -199,25 +191,20 @@ static void error(char *x)
        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)
+void
+decompress_kernel(int mmu_on, unsigned char *zimage_data,
+                 unsigned int zimage_len, unsigned long heap)
 {
-       insize = 0;
-       inptr = 0;
-       bytes_out = 0;
-       outcnt = 0;
-       output_data = 0;
-       output_ptr = CONFIG_MEMORY_START + 0x2000;
-       free_mem_ptr = (unsigned long)&_end;
+       output_data = (unsigned char *)CONFIG_MEMORY_START + 0x2000
+               + (mmu_on ? 0x80000000 : 0);
+       free_mem_ptr = heap;
        free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+       input_data = zimage_data;
+       input_len = zimage_len;
 
        makecrc();
        puts("Uncompressing Linux... ");
        gunzip();
        puts("Ok, booting the kernel.\n");
-       return bytes_out;
 }
index 20a9e94..a184317 100644 (file)
@@ -8,16 +8,24 @@ SECTIONS
 
   _text = .;
   .text : { *(.text) } = 0
-  .rodata : { *(.rodata) }
+  .rodata : { *(.rodata) *(.rodata.*) }
   _etext = .;
 
-  . = ALIGN(32) + (. & (32 - 1));
+  . = ALIGN(32 / 8);
   .data : { *(.data) }
+  . = ALIGN(32 / 8);
+  _got = .;
+  .got  : { *(.got) _egot = .; *(.got.*) }
   _edata  =  .;
 
   . = ALIGN(32 / 8);
   __bss_start = .;
-  .bss : { *(.bss) }
+  .bss : { *(.bss) *(.sbss) }
   . = ALIGN(32 / 8);
-  _end = . ;
+  _ebss = .;
+  . = ALIGN(4096);
+  . += 4096;
+  end = . ;
+
+  got_len = (_egot - _got);
 }
index a084903..924c799 100644 (file)
@@ -1,9 +1,9 @@
 SECTIONS
 {
   .data : {
-       input_len = .;
-       LONG(input_data_end - input_data) input_data = .;
+       zimage_data = .;
        *(.data)
-       input_data_end = .;
+       zimage_data_end = .;
        }
+  zimage_len = zimage_data_end - zimage_data;
 }
index 9be5917..1b95a8b 100644 (file)
@@ -24,7 +24,7 @@
 #define CPU_PARAMS     boot_cpu_data
 #define M32R_MCICAR     0xfffffff0
 #define M32R_MCDCAR     0xfffffff4
-#define        M32R_MCCR        0xfffffffc
+#define M32R_MCCR       0xfffffffc
 #define M32R_BSCR0      0xffffffd2
 
 ;BSEL
index 984701b..eeaad52 100644 (file)
@@ -1,5 +1,7 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1-bk21
+# Fri Nov 12 16:08:49 2004
 #
 CONFIG_M32R=y
 CONFIG_UID16=y
@@ -11,10 +13,12 @@ CONFIG_GENERIC_ISA_DMA=y
 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
@@ -24,17 +28,20 @@ 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_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
+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
@@ -44,6 +51,7 @@ 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
 
 #
@@ -77,22 +85,6 @@ 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)
 #
@@ -100,11 +92,20 @@ CONFIG_M32700UT_DS1302=y
 # CONFIG_ISA is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_PCMCIA=y
+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_PCC is not set
+CONFIG_M32R_CFC=y
+CONFIG_M32R_CFC_NUM=1
 
 #
 # PCI Hotplug Support
@@ -151,6 +152,16 @@ 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
@@ -170,7 +181,6 @@ CONFIG_BLK_DEV_IDECD=m
 # 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
@@ -213,9 +223,8 @@ CONFIG_SCSI_MULTI_LUN=y
 #
 # 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_QLOGIC_1280_1040 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -271,6 +280,9 @@ CONFIG_IP_PNP_DHCP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -290,7 +302,6 @@ CONFIG_IP_PNP_DHCP=y
 # 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
@@ -307,7 +318,50 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_NETDEVICES is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# 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
@@ -342,6 +396,7 @@ 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
@@ -355,7 +410,9 @@ CONFIG_SERIO_SERPORT=y
 #
 # Character devices
 #
-# CONFIG_VT is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -368,13 +425,12 @@ CONFIG_SERIO_SERPORT=y
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_M32R_SIO is not set
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
 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
@@ -387,6 +443,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
+CONFIG_DS1302=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
@@ -429,8 +486,8 @@ CONFIG_VIDEO_DEV=y
 # Video Adapters
 #
 # CONFIG_VIDEO_CPIA is not set
-CONFIG_M32R_AR=y
-CONFIG_M32R_AR_VGA=y
+CONFIG_VIDEO_M32R_AR=y
+CONFIG_VIDEO_M32R_AR_M64278=y
 
 #
 # Radio Adapters
@@ -445,7 +502,28 @@ CONFIG_M32R_AR_VGA=y
 #
 # Graphics support
 #
-# CONFIG_FB is not set
+CONFIG_FB=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING 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
@@ -455,6 +533,8 @@ CONFIG_M32R_AR_VGA=y
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
@@ -482,6 +562,7 @@ CONFIG_REISERFS_FS=m
 # 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
 
@@ -515,6 +596,7 @@ 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
 
@@ -549,6 +631,7 @@ 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
@@ -620,6 +703,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index 501b755..371ba90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/m32r/kernel/io_mappi.c
+ *  linux/arch/m32r/kernel/io_m32700ut.c
  *
  *  Typical I/O routines for M32700UT board.
  *
@@ -9,7 +9,6 @@
  *  This file is subject to the terms and conditions of the GNU General
  *  Public License.  See the file "COPYING" in the main directory of this
  *  archive for more details.
- *
  */
 
 #include <linux/config.h>
@@ -32,16 +31,16 @@ 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)
+#define PORT2ADDR(port)                _port2addr(port)
+#define PORT2ADDR_USB(port)    _port2addr_usb(port)
 
-static __inline__ void *_port2addr(unsigned long 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 inline void *__port2addr_ata(unsigned long port)
 {
        static int      dummy_reg;
 
@@ -67,16 +66,16 @@ static __inline__ void *__port2addr_ata(unsigned long port)
  */
 #define LAN_IOSTART    0x300
 #define LAN_IOEND      0x320
-static __inline__ void *_port2addr_ne(unsigned long port)
+static inline void *_port2addr_ne(unsigned long port)
 {
        return (void *)(port + NONCACHE_OFFSET + 0x10000000);
 }
-static __inline__ void *_port2addr_usb(unsigned long port)
+static inline void *_port2addr_usb(unsigned long port)
 {
-  return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000);
+       return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000);
 }
 
-static __inline__ void delay(void)
+static inline void delay(void)
 {
        __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
 }
@@ -87,29 +86,30 @@ static __inline__ void delay(void)
 
 #define PORT2ADDR_NE(port)  _port2addr_ne(port)
 
-static __inline__ unsigned char _ne_inb(void *portp)
+static inline unsigned char _ne_inb(void *portp)
 {
        return *(volatile unsigned char *)portp;
 }
 
-static __inline__ unsigned short _ne_inw(void *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)
+static inline void _ne_insb(void *portp, void *addr, unsigned long count)
 {
        unsigned char *buf = (unsigned char *)addr;
 
-       while (count--) *buf++ = _ne_inb(portp);
+       while (count--)
+               *buf++ = _ne_inb(portp);
 }
 
-static __inline__ void _ne_outb(unsigned char b, void *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)
+static inline void _ne_outw(unsigned short w, void *portp)
 {
        *(volatile unsigned short *)portp = cpu_to_le16(w);
 }
@@ -126,9 +126,9 @@ unsigned char _inb(unsigned long 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;
+               unsigned char b;
+               pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+               return b;
        } else
 #endif
 
@@ -146,13 +146,13 @@ unsigned short _inw(unsigned long port)
 #endif
 #if defined(CONFIG_USB)
        else if(port >= 0x340 && port < 0x3a0)
-         return *(volatile unsigned short *)PORT2ADDR_USB(port);
+               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;
+               unsigned short w;
+               pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+               return w;
        } else
 #endif
        return *(volatile unsigned short *)PORT2ADDR(port);
@@ -162,9 +162,9 @@ 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;
+               unsigned long l;
+               pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+               return l;
        } else
 #endif
        return *(volatile unsigned long *)PORT2ADDR(port);
@@ -184,9 +184,9 @@ unsigned char _inb_p(unsigned long port)
 #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;
+               unsigned char b;
+               pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+               return b;
        } else
 #endif
                v = *(volatile unsigned char *)PORT2ADDR(port);
@@ -208,15 +208,15 @@ unsigned short _inw_p(unsigned long port)
        } else
 #endif
 #if defined(CONFIG_USB)
-         if(port >= 0x340 && port < 0x3a0)
-           return *(volatile unsigned short *)PORT2ADDR_USB(port);
+       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;
+               unsigned short w;
+               pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+               return w;
        } else
 #endif
                v = *(volatile unsigned short *)PORT2ADDR(port);
@@ -246,7 +246,7 @@ void _outb(unsigned char b, unsigned long port)
 #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);
+               pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
        } else
 #endif
                *(volatile unsigned char *)PORT2ADDR(port) = b;
@@ -264,12 +264,12 @@ void _outw(unsigned short w, unsigned long port)
 #endif
 #if defined(CONFIG_USB)
        if(port >= 0x340 && port < 0x3a0)
-         *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+               *(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);
+               pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
        } else
 #endif
                *(volatile unsigned short *)PORT2ADDR(port) = w;
@@ -279,7 +279,7 @@ 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);
+               pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0);
        } else
 #endif
        *(volatile unsigned long *)PORT2ADDR(port) = l;
@@ -297,7 +297,7 @@ void _outb_p(unsigned char b, unsigned long port)
 #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);
+               pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
        } else
 #endif
                *(volatile unsigned char *)PORT2ADDR(port) = b;
@@ -316,13 +316,13 @@ void _outw_p(unsigned short w, unsigned long port)
        } else
 #endif
 #if defined(CONFIG_USB)
-         if(port >= 0x340 && port < 0x3a0)
-           *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+       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);
+               pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
        } else
 #endif
                *(volatile unsigned short *)PORT2ADDR(port) = w;
@@ -336,7 +336,7 @@ void _outl_p(unsigned long l, unsigned long port)
        delay();
 }
 
-void _insb(unsigned int port, void * addr, unsigned long count)
+void _insb(unsigned int port, void *addr, unsigned long count)
 {
        if (port >= LAN_IOSTART && port < LAN_IOEND)
                _ne_insb(PORT2ADDR_NE(port), addr, count);
@@ -344,22 +344,25 @@ void _insb(unsigned int port, void * addr, unsigned long count)
        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;
+               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);
+       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;
+               while (count--)
+                       *buf++ = *(volatile unsigned char *)portp;
        }
 }
 
-void _insw(unsigned int port, void * addr, unsigned long count)
+void _insw(unsigned int port, void *addr, unsigned long count)
 {
        unsigned short *buf = addr;
        unsigned short *portp;
@@ -370,55 +373,64 @@ void _insw(unsigned int port, void * addr, unsigned long count)
                 * from the DATA_REG. Do not swap the data.
                 */
                portp = PORT2ADDR_NE(port);
-               while (count--) *buf++ = *(volatile unsigned short *)portp;
+               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);
+               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;
+               while (count--)
+                       *buf++ = *(volatile unsigned short *)portp;
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while (count--) *buf++ = *(volatile unsigned short *)portp;
+               while (count--)
+                       *buf++ = *(volatile unsigned short *)portp;
        }
 }
 
-void _insl(unsigned int port, void * addr, unsigned long count)
+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;
+       while (count--)
+               *buf++ = *(volatile unsigned long *)portp;
 }
 
-void _outsb(unsigned int port, const void * addr, unsigned long count)
+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);
+               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++;
+               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);
+               pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char),
+                                count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned char *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned char *)portp = *buf++;
        }
 }
 
-void _outsw(unsigned int port, const void * addr, unsigned long count)
+void _outsw(unsigned int port, const void *addr, unsigned long count)
 {
        const unsigned short *buf = addr;
        unsigned short *portp;
@@ -429,27 +441,32 @@ void _outsw(unsigned int port, const void * addr, unsigned long count)
                 * into the DATA_REG. Do not swap the data.
                 */
                portp = PORT2ADDR_NE(port);
-               while(count--) *(volatile unsigned short *)portp = *buf++;
+               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++;
+               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);
+               pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short),
+                                count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned short *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned short *)portp = *buf++;
        }
 }
 
-void _outsl(unsigned int port, const void * addr, unsigned long count)
+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++;
+       while (count--)
+               *(volatile unsigned long *)portp = *buf++;
 }
index 74aeca6..85688ff 100644 (file)
@@ -7,15 +7,13 @@
  *                            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)
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
 #include <linux/types.h>
 
 #define M32R_PCC_IOMAP_SIZE 0x1000
 
 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 */
+#endif /* CONFIG_PCMCIA && CONFIG_M32R_PCC */
 
 #define PORT2ADDR(port)  _port2addr(port)
 
-static __inline__ void *_port2addr(unsigned long port)
+static inline void *_port2addr(unsigned long port)
 {
        return (void *)(port + NONCACHE_OFFSET);
 }
 
-static __inline__ void *_port2addr_ne(unsigned long port)
+static inline void *_port2addr_ne(unsigned long port)
 {
        return (void *)((port<<1) + NONCACHE_OFFSET + 0x0C000000);
 }
 
-static __inline__ void delay(void)
+static inline void delay(void)
 {
        __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
 }
@@ -52,12 +50,12 @@ static __inline__ void delay(void)
 
 #define PORT2ADDR_NE(port)  _port2addr_ne(port)
 
-static __inline__ unsigned char _ne_inb(void *portp)
+static inline unsigned char _ne_inb(void *portp)
 {
        return (unsigned char) *(volatile unsigned short *)portp;
 }
 
-static __inline__ unsigned short _ne_inw(void *portp)
+static inline unsigned short _ne_inw(void *portp)
 {
        unsigned short tmp;
 
@@ -65,12 +63,12 @@ static __inline__ unsigned short _ne_inw(void *portp)
        return le16_to_cpu(tmp);
 }
 
-static __inline__ void _ne_outb(unsigned char b, void *portp)
+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)
+static inline void _ne_outw(unsigned short w, void *portp)
 {
        *(volatile unsigned short *)portp = cpu_to_le16(w);
 }
@@ -80,15 +78,15 @@ 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 defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
         if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          unsigned char b;
-          pcc_ioread(0, port, &b, sizeof(b), 1, 0);
-          return b;
+               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;
+               unsigned char b;
+               pcc_ioread(1, port, &b, sizeof(b), 1, 0);
+               return b;
        } else
 #endif
 
@@ -100,15 +98,15 @@ 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 defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          unsigned short w;
-          pcc_ioread(0, port, &w, sizeof(w), 1, 0);
-          return w;
+               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;
+               unsigned short w;
+               pcc_ioread(1, port, &w, sizeof(w), 1, 0);
+               return w;
        } else
 #endif
        return *(volatile unsigned short *)PORT2ADDR(port);
@@ -116,15 +114,15 @@ unsigned short _inw(unsigned long port)
 
 unsigned long _inl(unsigned long port)
 {
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          unsigned long l;
-          pcc_ioread(0, port, &l, sizeof(l), 1, 0);
-          return l;
+               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;
+               unsigned short l;
+               pcc_ioread(1, port, &l, sizeof(l), 1, 0);
+               return l;
        } else
 #endif
        return *(volatile unsigned long *)PORT2ADDR(port);
@@ -137,15 +135,15 @@ unsigned char _inb_p(unsigned long port)
        if (port >= 0x300 && port < 0x320)
                v = _ne_inb(PORT2ADDR_NE(port));
        else
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          unsigned char b;
-          pcc_ioread(0, port, &b, sizeof(b), 1, 0);
-          return b;
+               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;
+               unsigned char b;
+               pcc_ioread(1, port, &b, sizeof(b), 1, 0);
+               return b;
        } else
 #endif
                v = *(volatile unsigned char *)PORT2ADDR(port);
@@ -161,15 +159,15 @@ unsigned short _inw_p(unsigned long port)
        if (port >= 0x300 && port < 0x320)
                v = _ne_inw(PORT2ADDR_NE(port));
        else
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          unsigned short w;
-          pcc_ioread(0, port, &w, sizeof(w), 1, 0);
-          return w;
+               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;
+               unsigned short w;
+               pcc_ioread(1, port, &w, sizeof(w), 1, 0);
+               return w;
        } else
 #endif
                v = *(volatile unsigned short *)PORT2ADDR(port);
@@ -192,11 +190,11 @@ 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 defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
+               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);
+               pcc_iowrite(1, port, &b, sizeof(b), 1, 0);
        } else
 #endif
                *(volatile unsigned char *)PORT2ADDR(port) = b;
@@ -207,11 +205,11 @@ 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 defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
+               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);
+               pcc_iowrite(1, port, &w, sizeof(w), 1, 0);
        } else
 #endif
                *(volatile unsigned short *)PORT2ADDR(port) = w;
@@ -219,11 +217,11 @@ void _outw(unsigned short w, unsigned long port)
 
 void _outl(unsigned long l, unsigned long port)
 {
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          pcc_iowrite(0, port, &l, sizeof(l), 1, 0);
+               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);
+               pcc_iowrite(1, port, &l, sizeof(l), 1, 0);
        } else
 #endif
        *(volatile unsigned long *)PORT2ADDR(port) = l;
@@ -234,11 +232,11 @@ 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 defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
+               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);
+               pcc_iowrite(1, port, &b, sizeof(b), 1, 0);
        } else
 #endif
                *(volatile unsigned char *)PORT2ADDR(port) = b;
@@ -251,11 +249,11 @@ 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 defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
+               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);
+               pcc_iowrite(1, port, &w, sizeof(w), 1, 0);
        } else
 #endif
                *(volatile unsigned short *)PORT2ADDR(port) = w;
@@ -269,100 +267,118 @@ void _outl_p(unsigned long l, unsigned long port)
        delay();
 }
 
-void _insb(unsigned int port, void * addr, unsigned long count)
+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)
+               while (count--)
+                       *buf++ = *(volatile unsigned char *)portp;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          pcc_ioread(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+               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);
+               pcc_ioread(1, port, (void *)addr, sizeof(unsigned char),
+                          count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *buf++ = *(volatile unsigned char *)portp;
+               while (count--)
+                       *buf++ = *(volatile unsigned char *)portp;
        }
 }
 
-void _insw(unsigned int port, void * addr, unsigned long count)
+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)
+               while (count--)
+                       *buf++ = _ne_inw(portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          pcc_ioread(0, port, (void *)addr, sizeof(unsigned short), count, 1);
+               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);
+               pcc_ioread(1, port, (void *)addr, sizeof(unsigned short),
+                          count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while (count--) *buf++ = *(volatile unsigned short *)portp;
+               while (count--)
+                       *buf++ = *(volatile unsigned short *)portp;
        }
 }
 
-void _insl(unsigned int port, void * addr, unsigned long count)
+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;
+       while (count--)
+               *buf++ = *(volatile unsigned long *)portp;
 }
 
-void _outsb(unsigned int port, const void * addr, unsigned long count)
+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)
+               while (count--)
+                       _ne_outb(*buf++, portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          pcc_iowrite(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+               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);
+               pcc_iowrite(1, port, (void *)addr, sizeof(unsigned char),
+                           count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned char *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned char *)portp = *buf++;
        }
 }
 
-void _outsw(unsigned int port, const void * addr, unsigned long count)
+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)
+               while (count--)
+                       _ne_outw(*buf++, portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
        } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
-          pcc_iowrite(0, port, (void *)addr, sizeof(unsigned short), count, 1);
+               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);
+               pcc_iowrite(1, port, (void *)addr, sizeof(unsigned short),
+                           count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned short *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned short *)portp = *buf++;
        }
 }
 
-void _outsl(unsigned int port, const void * addr, unsigned long count)
+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++;
+       while (count--)
+               *(volatile unsigned long *)portp = *buf++;
 }
index 7705fb0..4182cd4 100644 (file)
@@ -4,15 +4,14 @@
  *  Typical I/O routines for Mappi2 board.
  *
  *  Copyright (c) 2001-2003  Hiroyuki Kondo, Hirokazu Takata,
- *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ *                           Hitoshi Yamamoto, Mamoru Sakugawa
  */
 
-/* $Id:$ */
-
 #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>
@@ -32,29 +31,50 @@ extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
 #define PORT2ADDR_NE(port)   _port2addr_ne(port)
 #define PORT2ADDR_USB(port)  _port2addr_usb(port)
 
-static __inline__ void *_port2addr(unsigned long port)
+static inline void *_port2addr(unsigned long port)
 {
        return (void *)(port + NONCACHE_OFFSET);
 }
 
 #define LAN_IOSTART    0x300
 #define LAN_IOEND      0x320
+
+#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
+
 #ifdef CONFIG_CHIP_OPSP
-static __inline__ void *_port2addr_ne(unsigned long port)
+static inline void *_port2addr_ne(unsigned long port)
 {
        return (void *)(port + NONCACHE_OFFSET + 0x10000000);
 }
 #else
-static __inline__ void *_port2addr_ne(unsigned long port)
+static inline void *_port2addr_ne(unsigned long port)
 {
        return (void *)(port + NONCACHE_OFFSET + 0x04000000);
 }
 #endif
-static __inline__ void *_port2addr_usb(unsigned long port)
+static inline void *_port2addr_usb(unsigned long port)
 {
        return (void *)(port + NONCACHE_OFFSET + 0x14000000);
 }
-static __inline__ void delay(void)
+static inline void delay(void)
 {
        __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
 }
@@ -63,51 +83,48 @@ static __inline__ void delay(void)
  * NIC I/O function
  */
 
-static __inline__ unsigned char _ne_inb(void *portp)
+static inline unsigned char _ne_inb(void *portp)
 {
        return (unsigned char) *(volatile unsigned char *)portp;
 }
 
-static __inline__ unsigned short _ne_inw(void *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
+       return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp);
 }
 
-static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count)
+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;
+       while (count--)
+               *buf++ = *(volatile unsigned char *)portp;
 }
 
-static __inline__ void _ne_outb(unsigned char b, void *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)
+static inline void _ne_outw(unsigned short w, void *portp)
 {
-       *(volatile unsigned short *)portp = (w>>8|w<<8);
+       *(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;
+               unsigned char b;
+               pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+               return b;
        } else
 #endif
 
@@ -118,16 +135,21 @@ 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);
+       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 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);
@@ -137,9 +159,9 @@ 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;
+               unsigned long l;
+               pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+               return l;
        } else
 #endif
        return *(volatile unsigned long *)PORT2ADDR(port);
@@ -149,14 +171,19 @@ unsigned char _inb_p(unsigned long port)
 {
        unsigned char  v;
 
-       if (port >= 0x300 && port < 0x320)
+       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;
+               unsigned char b;
+               pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+               return b;
        } else
 #endif
                v = *(volatile unsigned char *)PORT2ADDR(port);
@@ -169,19 +196,24 @@ unsigned short _inw_p(unsigned long port)
 {
        unsigned short  v;
 
-       if (port >= 0x300 && port < 0x320)
+       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)
+       if (port >= 0x340 && port < 0x3a0)
                v = *(volatile unsigned short *)PORT2ADDR_USB(port);
-         else
+       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;
+               unsigned short w;
+               pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+               return w;
        } else
 #endif
                v = *(volatile unsigned short *)PORT2ADDR(port);
@@ -204,9 +236,14 @@ 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);
+               pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
        } else
 #endif
                *(volatile unsigned char *)PORT2ADDR(port) = b;
@@ -217,14 +254,19 @@ 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;
+       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);
+               pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
        } else
 #endif
                *(volatile unsigned short *)PORT2ADDR(port) = w;
@@ -234,7 +276,7 @@ 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);
+               pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0);
        } else
 #endif
        *(volatile unsigned long *)PORT2ADDR(port) = l;
@@ -245,9 +287,14 @@ 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);
+               pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
        } else
 #endif
                *(volatile unsigned char *)PORT2ADDR(port) = b;
@@ -260,6 +307,11 @@ 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;
@@ -267,7 +319,7 @@ void _outw_p(unsigned short w, unsigned long port)
 #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);
+               pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
        } else
 #endif
                *(volatile unsigned short *)PORT2ADDR(port) = w;
@@ -285,15 +337,25 @@ 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);
+       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;
+               while (count--)
+                       *buf++ = *(volatile unsigned char *)portp;
        }
 }
 
@@ -302,16 +364,25 @@ void _insw(unsigned int port, void * addr, unsigned long count)
        unsigned short *buf = addr;
        unsigned short *portp;
 
-       if (port >= LAN_IOSTART && port < LAN_IOEND)
+       if (port >= LAN_IOSTART && port < LAN_IOEND) {
                portp = PORT2ADDR_NE(port);
-               while (count--) *buf++ = *(volatile unsigned short *)portp;
+               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);
+               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;
+               while (count--)
+                       *buf++ = *(volatile unsigned short *)portp;
        }
 }
 
@@ -321,7 +392,8 @@ void _insl(unsigned int port, void * addr, unsigned long count)
        unsigned long *portp;
 
        portp = PORT2ADDR(port);
-       while (count--) *buf++ = *(volatile unsigned long *)portp;
+       while (count--)
+               *buf++ = *(volatile unsigned long *)portp;
 }
 
 void _outsb(unsigned int port, const void * addr, unsigned long count)
@@ -329,16 +401,25 @@ 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)
+       if (port >= LAN_IOSTART && port < LAN_IOEND) {
                portp = PORT2ADDR_NE(port);
-               while (count--) _ne_outb(*buf++, portp);
+               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);
+               pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char),
+                                count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned char *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned char *)portp = *buf++;
        }
 }
 
@@ -347,16 +428,25 @@ 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)
+       if (port >= LAN_IOSTART && port < LAN_IOEND) {
                portp = PORT2ADDR_NE(port);
-               while (count--) *(volatile unsigned short *)portp = *buf++;
+               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);
+               pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short),
+                                count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned short *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned short *)portp = *buf++;
        }
 }
 
@@ -366,5 +456,6 @@ void _outsl(unsigned int port, const void * addr, unsigned long count)
        unsigned char *portp;
 
        portp = PORT2ADDR(port);
-       while(count--) *(volatile unsigned long *)portp = *buf++;
+       while (count--)
+               *(volatile unsigned long *)portp = *buf++;
 }
index 7fcbf20..2869647 100644 (file)
@@ -4,11 +4,9 @@
  *  Typical I/O routines for OAKS32R board.
  *
  *  Copyright (c) 2001-2004  Hiroyuki Kondo, Hirokazu Takata,
- *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ *                           Hitoshi Yamamoto, Mamoru Sakugawa
  */
 
-/* $Id$ */
-
 #include <linux/config.h>
 #include <asm/m32r.h>
 #include <asm/page.h>
 
 #define PORT2ADDR(port)  _port2addr(port)
 
-static __inline__ void *_port2addr(unsigned long port)
+static inline void *_port2addr(unsigned long port)
 {
        return (void *)(port + NONCACHE_OFFSET);
 }
 
-static __inline__  void *_port2addr_ne(unsigned long port)
+static inline  void *_port2addr_ne(unsigned long port)
 {
        return (void *)((port<<1) + NONCACHE_OFFSET + 0x02000000);
 }
 
-static __inline__ void delay(void)
+static inline void delay(void)
 {
        __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
 }
@@ -37,12 +35,12 @@ static __inline__ void delay(void)
 
 #define PORT2ADDR_NE(port)  _port2addr_ne(port)
 
-static __inline__ unsigned char _ne_inb(void *portp)
+static inline unsigned char _ne_inb(void *portp)
 {
        return *(volatile unsigned char *)(portp+1);
 }
 
-static __inline__ unsigned short _ne_inw(void *portp)
+static inline unsigned short _ne_inw(void *portp)
 {
        unsigned short tmp;
 
@@ -51,21 +49,22 @@ static __inline__ unsigned short _ne_inw(void *portp)
        return tmp;
 }
 
-static __inline__  void _ne_insb(void *portp, void * addr, unsigned long count)
+static inline  void _ne_insb(void *portp, void *addr, unsigned long count)
 {
        unsigned char *buf = addr;
-       while (count--) *buf++ = *(volatile unsigned char *)(portp+1);
+       while (count--)
+               *buf++ = *(volatile unsigned char *)(portp+1);
 }
 
-static __inline__ void _ne_outb(unsigned char b, void *portp)
+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)
+static inline void _ne_outw(unsigned short w, void *portp)
 {
-  *(volatile unsigned short *)portp =  (w >> 8);
-  *(volatile unsigned short *)(portp+2) =  (w & 0xff);
+       *(volatile unsigned short *)portp =  (w >> 8);
+       *(volatile unsigned short *)(portp+2) =  (w & 0xff);
 }
 
 unsigned char _inb(unsigned long port)
@@ -171,73 +170,82 @@ void _outl_p(unsigned long l, unsigned long port)
        delay();
 }
 
-void _insb(unsigned int port, void * addr, unsigned long count)
+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;
+               while (count--)
+                       *buf++ = *(volatile unsigned char *)portp;
        }
 }
 
-void _insw(unsigned int port, void * addr, unsigned long count)
+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);
+               while (count--)
+                       *buf++ = _ne_inw(portp);
        } else {
                portp = PORT2ADDR(port);
-               while (count--) *buf++ = *(volatile unsigned short *)portp;
+               while (count--)
+                       *buf++ = *(volatile unsigned short *)portp;
        }
 }
 
-void _insl(unsigned int port, void * addr, unsigned long count)
+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;
+       while (count--)
+               *buf++ = *(volatile unsigned long *)portp;
 }
 
-void _outsb(unsigned int port, const void * addr, unsigned long count)
+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);
+               while (count--)
+                       _ne_outb(*buf++, portp);
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned char *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned char *)portp = *buf++;
        }
 }
 
-void _outsw(unsigned int port, const void * addr, unsigned long count)
+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);
+               while (count--)
+                       _ne_outw(*buf++, portp);
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned short *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned short *)portp = *buf++;
        }
 }
 
-void _outsl(unsigned int port, const void * addr, unsigned long count)
+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++;
+       while (count--)
+               *(volatile unsigned long *)portp = *buf++;
 }
index 642376e..aaf42f9 100644 (file)
@@ -9,7 +9,6 @@
  *  This file is subject to the terms and conditions of the GNU General
  *  Public License.  See the file "COPYING" in the main directory of this
  *  archive for more details.
- *
  */
 
 #include <linux/config.h>
@@ -35,7 +34,7 @@ extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
 #define PORT2ADDR(port)  _port2addr(port)
 #define PORT2ADDR_USB(port) _port2addr_usb(port)
 
-static __inline__ void *_port2addr(unsigned long port)
+static inline void *_port2addr(unsigned long port)
 {
        return (void *)(port + NONCACHE_OFFSET);
 }
@@ -47,16 +46,16 @@ static __inline__ void *_port2addr(unsigned long port)
  */
 #define LAN_IOSTART    0x300
 #define LAN_IOEND      0x320
-static __inline__ void *_port2addr_ne(unsigned long port)
+static inline void *_port2addr_ne(unsigned long port)
 {
        return (void *)(port + NONCACHE_OFFSET + 0x10000000);
 }
-static __inline__ void *_port2addr_usb(unsigned long port)
+static inline void *_port2addr_usb(unsigned long port)
 {
-  return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000);
+       return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000);
 }
 
-static __inline__ void delay(void)
+static inline void delay(void)
 {
        __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
 }
@@ -67,29 +66,30 @@ static __inline__ void delay(void)
 
 #define PORT2ADDR_NE(port)  _port2addr_ne(port)
 
-static __inline__ unsigned char _ne_inb(void *portp)
+static inline unsigned char _ne_inb(void *portp)
 {
        return *(volatile unsigned char *)portp;
 }
 
-static __inline__ unsigned short _ne_inw(void *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)
+static inline void _ne_insb(void *portp, void *addr, unsigned long count)
 {
        unsigned char *buf = (unsigned char *)addr;
 
-       while (count--) *buf++ = _ne_inb(portp);
+       while (count--)
+               *buf++ = _ne_inb(portp);
 }
 
-static __inline__ void _ne_outb(unsigned char b, void *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)
+static inline void _ne_outw(unsigned short w, void *portp)
 {
        *(volatile unsigned short *)portp = cpu_to_le16(w);
 }
@@ -101,9 +101,9 @@ unsigned char _inb(unsigned long 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;
+               unsigned char b;
+               pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+               return b;
        } else
 #endif
 
@@ -116,14 +116,14 @@ unsigned short _inw(unsigned long port)
                return _ne_inw(PORT2ADDR_NE(port));
 #if defined(CONFIG_USB)
        else if(port >= 0x340 && port < 0x3a0)
-         return *(volatile unsigned short *)PORT2ADDR_USB(port);
+               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 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);
@@ -133,9 +133,9 @@ 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;
+               unsigned long l;
+               pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+               return l;
        } else
 #endif
        return *(volatile unsigned long *)PORT2ADDR(port);
@@ -150,9 +150,9 @@ unsigned char _inb_p(unsigned long 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;
+               unsigned char b;
+               pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+               return b;
        } else
 #endif
                v = *(volatile unsigned char *)PORT2ADDR(port);
@@ -169,16 +169,16 @@ unsigned short _inw_p(unsigned long port)
                v = _ne_inw(PORT2ADDR_NE(port));
        else
 #if defined(CONFIG_USB)
-         if(port >= 0x340 && port < 0x3a0)
-           return *(volatile unsigned short *)PORT2ADDR_USB(port);
+       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;
+               unsigned short w;
+               pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+               return w;
        } else
 #endif
                v = *(volatile unsigned short *)PORT2ADDR(port);
@@ -203,7 +203,7 @@ void _outb(unsigned char b, unsigned long 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);
+               pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
        } else
 #endif
                *(volatile unsigned char *)PORT2ADDR(port) = b;
@@ -216,13 +216,13 @@ void _outw(unsigned short w, unsigned long port)
        else
 #if defined(CONFIG_USB)
        if(port >= 0x340 && port < 0x3a0)
-         *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+               *(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);
+               pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
        } else
 #endif
                *(volatile unsigned short *)PORT2ADDR(port) = w;
@@ -232,7 +232,7 @@ 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);
+               pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0);
        } else
 #endif
        *(volatile unsigned long *)PORT2ADDR(port) = l;
@@ -245,7 +245,7 @@ void _outb_p(unsigned char b, unsigned long 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);
+               pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
        } else
 #endif
                *(volatile unsigned char *)PORT2ADDR(port) = b;
@@ -259,14 +259,14 @@ void _outw_p(unsigned short w, unsigned long port)
                _ne_outw(w, PORT2ADDR_NE(port));
        else
 #if defined(CONFIG_USB)
-         if(port >= 0x340 && port < 0x3a0)
-           *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+       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);
+               pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
        } else
 #endif
                *(volatile unsigned short *)PORT2ADDR(port) = w;
@@ -280,23 +280,25 @@ void _outl_p(unsigned long l, unsigned long port)
        delay();
 }
 
-void _insb(unsigned int port, void * addr, unsigned long count)
+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);
+       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;
+               while (count--)
+                       *buf++ = *(volatile unsigned char *)portp;
        }
 }
 
-void _insw(unsigned int port, void * addr, unsigned long count)
+void _insw(unsigned int port, void *addr, unsigned long count)
 {
        unsigned short *buf = addr;
        unsigned short *portp;
@@ -307,45 +309,52 @@ void _insw(unsigned int port, void * addr, unsigned long count)
                 * from the DATA_REG. Do not swap the data.
                 */
                portp = PORT2ADDR_NE(port);
-               while (count--) *buf++ = *(volatile unsigned short *)portp;
+               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);
+               pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short),
+                               count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while (count--) *buf++ = *(volatile unsigned short *)portp;
+               while (count--)
+                       *buf++ = *(volatile unsigned short *)portp;
        }
 }
 
-void _insl(unsigned int port, void * addr, unsigned long count)
+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;
+       while (count--)
+               *buf++ = *(volatile unsigned long *)portp;
 }
 
-void _outsb(unsigned int port, const void * addr, unsigned long count)
+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);
+               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);
+               pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char),
+                                count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned char *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned char *)portp = *buf++;
        }
 }
 
-void _outsw(unsigned int port, const void * addr, unsigned long count)
+void _outsw(unsigned int port, const void *addr, unsigned long count)
 {
        const unsigned short *buf = addr;
        unsigned short *portp;
@@ -356,22 +365,26 @@ void _outsw(unsigned int port, const void * addr, unsigned long count)
                 * into the DATA_REG. Do not swap the data.
                 */
                portp = PORT2ADDR_NE(port);
-               while(count--) *(volatile unsigned short *)portp = *buf++;
+               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);
+               pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short),
+                                count, 1);
 #endif
        } else {
                portp = PORT2ADDR(port);
-               while(count--) *(volatile unsigned short *)portp = *buf++;
+               while (count--)
+                       *(volatile unsigned short *)portp = *buf++;
        }
 }
 
-void _outsl(unsigned int port, const void * addr, unsigned long count)
+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++;
+       while (count--)
+               *(volatile unsigned long *)portp = *buf++;
 }
index cc77ced..27928a0 100644 (file)
@@ -178,7 +178,8 @@ void _insb(unsigned int port, void * addr, unsigned long count)
        else {
                unsigned char *buf = addr;
                unsigned char *portp = PORT2ADDR(port);
-               while(count--) *buf++ = *(volatile unsigned char *)portp;
+               while (count--)
+                       *buf++ = *(volatile unsigned char *)portp;
        }
 }
 
@@ -192,7 +193,8 @@ void _insw(unsigned int port, void * addr, unsigned long count)
                        1);
        else {
                portp = PORT2ADDR(port);
-               while (count--) *buf++ = *(volatile unsigned short *)portp;
+               while (count--)
+                       *buf++ = *(volatile unsigned short *)portp;
        }
 }
 
index ba13577..74ab2ec 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/kallsyms.h>
+#include <linux/bitops.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>
index 9e7de27..4723ce6 100644 (file)
@@ -247,8 +247,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long spu,
        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;
@@ -335,8 +333,11 @@ asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv, c
                goto out;
 
        error = do_execve(filename, uargv, uenvp, &regs);
-       if (error == 0)
+       if (error == 0) {
+               task_lock(current);
                current->ptrace &= ~PT_DTRACE;
+               task_unlock(current);
+       }
        putname(filename);
 out:
        return error;
index ab4137a..6d58f97 100644 (file)
@@ -713,7 +713,7 @@ do_ptrace(long request, struct task_struct *child, long addr, long data)
                ret = 0;
                unregister_all_debug_traps(child);
                invalidate_cache();
-               if (child->state == TASK_ZOMBIE)        /* already dead */
+               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
                        break;
                child->exit_code = SIGKILL;
                wake_up_process(child);
index 5d0780b..488aa87 100644 (file)
@@ -435,7 +435,7 @@ void __init init_IRQ(void)
        icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
        enable_m32700ut_irq(M32R_IRQ_INT2);
 
-//#if defined(CONFIG_M32R_AR_VGA)
+//#if defined(CONFIG_VIDEO_M32R_AR)
        /*
         * INT3# is used for AR
         */
@@ -445,7 +445,7 @@ void __init init_IRQ(void)
        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 */
+//#endif       /* CONFIG_VIDEO_M32R_AR */
 }
 
 #define LAN_IOSTART     0x300
index 523cee3..1e74110 100644 (file)
@@ -140,7 +140,7 @@ void __init init_IRQ(void)
        disable_mappi_irq(M32R_IRQ_SIO1_S);
 #endif /* CONFIG_SERIAL_M32R_SIO */
 
-#if defined(CONFIG_M32RPCC)
+#if defined(CONFIG_M32R_PCC)
        /* INT1 : pccard0 interrupt */
        irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
        irq_desc[M32R_IRQ_INT1].handler = &mappi_irq_type;
index 92eb06e..1904d46 100644 (file)
@@ -151,7 +151,6 @@ void __init init_IRQ(void)
        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;
@@ -161,6 +160,7 @@ void __init init_IRQ(void)
        icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
        disable_mappi2_irq(PLD_IRQ_CFIREQ);
 
+#if defined(CONFIG_M32R_CFC)
        /* ICUCR41: CFC Insert */
        irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
        irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi2_irq_type;
index 17a4d3e..84315e3 100644 (file)
@@ -439,7 +439,7 @@ void __init init_IRQ(void)
        icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
        enable_opsput_irq(M32R_IRQ_INT2);
 
-//#if defined(CONFIG_M32R_AR_VGA)
+//#if defined(CONFIG_VIDEO_M32R_AR)
        /*
         * INT3# is used for AR
         */
@@ -449,7 +449,7 @@ void __init init_IRQ(void)
        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 */
+//#endif       /* CONFIG_VIDEO_M32R_AR */
 }
 
 #define LAN_IOSTART     0x300
index 6ac4f70..e80a6d5 100644 (file)
@@ -433,7 +433,7 @@ int __init start_secondary(void *unused)
        cpu_init();
        smp_callin();
        while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
-               rep_nop();
+               cpu_relax();
 
        smp_online();
 
@@ -482,7 +482,7 @@ static void __init smp_callin(void)
                /* Has the boot CPU finished it's STARTUP sequence ? */
                if (cpu_isset(cpu_id, cpu_callout_map))
                        break;
-               rep_nop();
+               cpu_relax();
        }
 
        if (!time_before(jiffies, timeout)) {
index f34fa19..435619e 100644 (file)
@@ -57,10 +57,10 @@ asmlinkage int sys_tas(int *addr)
        if (!access_ok(VERIFY_WRITE, addr, sizeof (int)))
                return -EFAULT;
 
-       spin_lock(&tas_lock);
+       _raw_spin_lock(&tas_lock);
        oldval = *addr;
        *addr = 1;
-       spin_unlock(&tas_lock);
+       _raw_spin_unlock(&tas_lock);
 
        return oldval;
 }
index 25a3166..3c47072 100644 (file)
@@ -193,7 +193,7 @@ EXPORT_SYMBOL(do_settimeofday);
  * 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)
+static inline int set_rtc_mmss(unsigned long nowtime)
 {
        return 0;
 }
@@ -205,11 +205,17 @@ 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)
+static inline void
+do_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
+#ifndef CONFIG_SMP
+       profile_tick(CPU_PROFILING, regs);
+#endif
        do_timer(regs);
 
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
        /*
         * If we have an externally synchronized Linux clock, then update
         * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
@@ -241,10 +247,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        do_timer_interrupt(irq, NULL, regs);
        write_sequnlock(&xtime_lock);
 
-#ifndef CONFIG_SMP
-       profile_tick(CPU_PROFILING, regs);
-#endif
-
        return IRQ_HANDLED;
 }
 
@@ -273,8 +275,8 @@ void __init time_init(void)
 
        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;
+       set_normalized_timespec(&wall_to_monotonic,
+               -xtime.tv_sec, -xtime.tv_nsec);
 
 #if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \
        || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \
@@ -314,4 +316,3 @@ unsigned long long sched_clock(void)
 {
        return (unsigned long long)jiffies * (1000000000 / HZ);
 }
-
index 7afe66e..fb29632 100644 (file)
@@ -51,7 +51,7 @@ void __delay(unsigned long loops)
                "addi   %0, #-1                 \n\t"
                "bgtz   %0, 1b                  \n\t"
                " .fillinsn                     \n\t"
-               "2:i                            \n\t"
+               "2:                             \n\t"
                : "+r" (loops)
                : "r" (0)
        );
index 7fe94b6..6e26df1 100644 (file)
@@ -70,16 +70,18 @@ qword_set_loop:
        st      r1, @+r4
        bnc     qword_set_loop      ||  cmpz    r2
        jc      r14
-word_set_wrap:
+set_remainder:
        cmpui   r2, #4
-       bc      byte_set
+       bc      byte_set_wrap1
        addi    r2, #-4
        bra     word_set_loop
 
 byte_set_wrap:
        addi    r2, #4
-       addi    r4, #4              ||  cmpz    r2
+       cmpz    r2
        jc      r14
+byte_set_wrap1:
+       addi    r4, #4
 #if defined(CONFIG_ISA_M32R2)
 byte_set:
        addi    r2, #-1             ||  stb     r1, @r4+
@@ -153,18 +155,19 @@ qword_set_loop:
        st      r1, @+r4
        st      r1, @+r4
        bnc     qword_set_loop
-       bnez    r2, word_set_wrap
+       bnez    r2, set_remainder
        jmp     r14
-word_set_wrap:
+set_remainder:
        cmpui   r2, #4
-       bc      byte_set
+       bc      byte_set_wrap1
        addi    r2, #-4
        bra     word_set_loop
 
 byte_set_wrap:
        addi    r2, #4
-       addi    r4, #4
        beqz    r2, end_memset
+byte_set_wrap1:
+       addi    r4, #4
 byte_set:
        addi    r2, #-1
        stb     r1, @r4
index df7f9d0..940b651 100644 (file)
@@ -1,5 +1,7 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1-bk21
+# Fri Nov 12 16:08:45 2004
 #
 CONFIG_M32R=y
 CONFIG_UID16=y
@@ -10,10 +12,12 @@ CONFIG_GENERIC_ISA_DMA=y
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -23,17 +27,20 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=15
 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_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
+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
@@ -43,6 +50,7 @@ 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
 CONFIG_STOP_MACHINE=y
 
@@ -80,22 +88,6 @@ 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)
 #
@@ -103,11 +95,20 @@ CONFIG_M32700UT_DS1302=y
 # CONFIG_ISA is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_PCMCIA=y
+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_PCC is not set
+CONFIG_M32R_CFC=y
+CONFIG_M32R_CFC_NUM=1
 
 #
 # PCI Hotplug Support
@@ -154,6 +155,16 @@ 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
@@ -173,7 +184,6 @@ CONFIG_BLK_DEV_IDECD=m
 # 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
@@ -216,9 +226,8 @@ CONFIG_SCSI_MULTI_LUN=y
 #
 # 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_QLOGIC_1280_1040 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -274,6 +283,9 @@ CONFIG_IP_PNP_DHCP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -293,7 +305,6 @@ CONFIG_IP_PNP_DHCP=y
 # 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
@@ -310,7 +321,50 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_NETDEVICES is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# 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
@@ -345,6 +399,7 @@ 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
@@ -373,13 +428,12 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_M32R_SIO is not set
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
 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
@@ -392,6 +446,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
+CONFIG_DS1302=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
@@ -434,8 +489,8 @@ CONFIG_VIDEO_DEV=y
 # Video Adapters
 #
 # CONFIG_VIDEO_CPIA is not set
-CONFIG_M32R_AR=y
-CONFIG_M32R_AR_VGA=y
+CONFIG_VIDEO_M32R_AR=y
+CONFIG_VIDEO_M32R_AR_M64278=y
 
 #
 # Radio Adapters
@@ -451,14 +506,14 @@ CONFIG_M32R_AR_VGA=y
 # Graphics support
 #
 CONFIG_FB=y
-CONFIG_FB_EPSON_S1D13806=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
 # 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
@@ -472,7 +527,6 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
-CONFIG_LOGO_M32R_CLUT224=y
 
 #
 # Sound
@@ -482,6 +536,8 @@ CONFIG_LOGO_M32R_CLUT224=y
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
@@ -509,6 +565,7 @@ CONFIG_REISERFS_FS=m
 # 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
 
@@ -542,6 +599,7 @@ 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
 
@@ -576,6 +634,7 @@ 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
@@ -647,6 +706,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index 5a9da73..eeaad52 100644 (file)
@@ -1,5 +1,7 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1-bk21
+# Fri Nov 12 16:08:49 2004
 #
 CONFIG_M32R=y
 CONFIG_UID16=y
@@ -11,10 +13,12 @@ CONFIG_GENERIC_ISA_DMA=y
 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
@@ -24,17 +28,20 @@ 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_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
+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
@@ -44,6 +51,7 @@ 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
 
 #
@@ -77,22 +85,6 @@ 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)
 #
@@ -100,11 +92,20 @@ CONFIG_M32700UT_DS1302=y
 # CONFIG_ISA is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_PCMCIA=y
+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_PCC is not set
+CONFIG_M32R_CFC=y
+CONFIG_M32R_CFC_NUM=1
 
 #
 # PCI Hotplug Support
@@ -151,6 +152,16 @@ 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
@@ -170,7 +181,6 @@ CONFIG_BLK_DEV_IDECD=m
 # 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
@@ -213,9 +223,8 @@ CONFIG_SCSI_MULTI_LUN=y
 #
 # 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_QLOGIC_1280_1040 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -271,6 +280,9 @@ CONFIG_IP_PNP_DHCP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -290,7 +302,6 @@ CONFIG_IP_PNP_DHCP=y
 # 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
@@ -307,7 +318,50 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_NETDEVICES is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# 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
@@ -342,6 +396,7 @@ 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
@@ -370,13 +425,12 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_M32R_SIO is not set
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
 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
@@ -389,6 +443,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
+CONFIG_DS1302=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
@@ -431,8 +486,8 @@ CONFIG_VIDEO_DEV=y
 # Video Adapters
 #
 # CONFIG_VIDEO_CPIA is not set
-CONFIG_M32R_AR=y
-CONFIG_M32R_AR_VGA=y
+CONFIG_VIDEO_M32R_AR=y
+CONFIG_VIDEO_M32R_AR_M64278=y
 
 #
 # Radio Adapters
@@ -448,14 +503,14 @@ CONFIG_M32R_AR_VGA=y
 # Graphics support
 #
 CONFIG_FB=y
-CONFIG_FB_EPSON_S1D13806=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
 # 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
@@ -469,7 +524,6 @@ CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
-CONFIG_LOGO_M32R_CLUT224=y
 
 #
 # Sound
@@ -479,6 +533,8 @@ CONFIG_LOGO_M32R_CLUT224=y
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
@@ -506,6 +562,7 @@ CONFIG_REISERFS_FS=m
 # 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
 
@@ -539,6 +596,7 @@ 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
 
@@ -573,6 +631,7 @@ 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
@@ -644,6 +703,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index fa79cd9..525dab4 100644 (file)
@@ -1,5 +1,5 @@
 # .gdbinit file
-# $Id: dot.gdbinit_200MHz_16MB,v 1.1 2004/08/17 02:58:11 takata Exp $
+# $Id: dot.gdbinit_200MHz_16MB,v 1.2 2004/10/20 03:02: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).
@@ -178,11 +178,11 @@ end
 
 # Set kernel parameters
 define set_kernel_parameters
-  set $param = (void*)0x08002000
+  set $param = (void*)0x08001000
   # INITRD_START
-  set *(unsigned long *)($param + 0x0010) = 0x082a0000
+#  set *(unsigned long *)($param + 0x0010) = 0x08300000
   # INITRD_SIZE
-  set *(unsigned long *)($param + 0x0014) = 0x00000000
+#  set *(unsigned long *)($param + 0x0014) = 0x00000000
   # M32R_CPUCLK
   set *(unsigned long *)($param + 0x0018) = 0d200000000
   # M32R_BUSCLK
@@ -191,15 +191,15 @@ define set_kernel_parameters
   # 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"
+  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=16M \0"
 end
 
 # Boot
 define boot
   set_kernel_parameters
   set $fp = 0
-  set $pc = 0x08001000
-  set *(unsigned char *)0xffffffff = 0x03
+  set $pc = 0x08002000
+# set *(unsigned char *)0xffffffff = 0x03
   si
   c
 end
index 4df06e1..aa50365 100644 (file)
@@ -1,5 +1,5 @@
 # .gdbinit file
-# $Id: dot.gdbinit_300MHz_32MB,v 1.1 2004/08/17 02:58:11 takata Exp $
+# $Id: dot.gdbinit_300MHz_32MB,v 1.2 2004/10/20 03:02: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).
@@ -42,8 +42,8 @@ define sdram_init
   set *(unsigned long *)0x00ef602c = 0x00000020
   # Ch0-TR
   set *(unsigned long *)0x00ef6028 = 0x00051502
-  # Ch0-ADR (size:16MB)
-  set *(unsigned long *)0x00ef6020 = 0x08000002
+  # Ch0-ADR (size:32MB)
+  set *(unsigned long *)0x00ef6020 = 0x08000003
   # AutoRef On
   set *(unsigned long *)0x00ef6004 = 0x00010e24
   # Access enable
@@ -51,7 +51,7 @@ define sdram_init
 end
 document sdram_init
   SDRAM controller initialization
-  0x08000000 - 0x08ffffff (16MB)
+  0x08000000 - 0x09ffffff (32MB)
 end
 
 # Initialize BSEL3 for UT-CFC
@@ -161,8 +161,8 @@ define setup
   shell sleep 0.1
   clock_init
   shell sleep 0.1
-  # SDRAM: 16MB
-  set *(unsigned long *)0x00ef6020 = 0x08000002
+  # SDRAM: 32MB
+  set *(unsigned long *)0x00ef6020 = 0x08000003
   cfc_init
   # USB
   set *(unsigned short *)0xb0301000 = 0x100
@@ -178,11 +178,11 @@ end
 
 # Set kernel parameters
 define set_kernel_parameters
-  set $param = (void*)0x08002000
+  set $param = (void*)0x08001000
   # INITRD_START
-  set *(unsigned long *)($param + 0x0010) = 0x082a0000
+#  set *(unsigned long *)($param + 0x0010) = 0x08300000
   # INITRD_SIZE
-  set *(unsigned long *)($param + 0x0014) = 0x00000000
+#  set *(unsigned long *)($param + 0x0014) = 0x00000000
   # M32R_CPUCLK
   set *(unsigned long *)($param + 0x0018) = 0d300000000
   # M32R_BUSCLK
@@ -191,15 +191,15 @@ define set_kernel_parameters
   # 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"
+  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 = 0x08001000
-  set *(unsigned char *)0xffffffff = 0x03
+  set $pc = 0x08002000
+# set *(unsigned char *)0xffffffff = 0x03
   si
   c
 end
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
+
index cae54bf..429293e 100644 (file)
@@ -1,5 +1,7 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1-bk21
+# Fri Nov 12 16:08:51 2004
 #
 CONFIG_M32R=y
 CONFIG_UID16=y
@@ -11,10 +13,12 @@ CONFIG_GENERIC_ISA_DMA=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 # CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
@@ -22,17 +26,20 @@ 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_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
+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
@@ -42,6 +49,7 @@ 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
 
 #
@@ -75,17 +83,6 @@ 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)
 #
@@ -93,9 +90,18 @@ CONFIG_M32R_NE2000=y
 # CONFIG_ISA is not set
 
 #
-# PCMCIA/CardBus support
+# 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_PCMCIA is not set
+# CONFIG_TCIC is not set
+CONFIG_M32R_PCC=y
 
 #
 # PCI Hotplug Support
@@ -144,6 +150,16 @@ 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
@@ -199,6 +215,9 @@ CONFIG_IP_PNP_DHCP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -218,7 +237,6 @@ CONFIG_IP_PNP_DHCP=y
 # 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
@@ -235,7 +253,48 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_NETDEVICES is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NE2000=y
+
+#
+# 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
@@ -270,6 +329,7 @@ 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
@@ -302,7 +362,6 @@ CONFIG_SERIAL_M32R_SIO_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -323,6 +382,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # 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
 
 #
@@ -362,6 +426,8 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
@@ -381,6 +447,7 @@ CONFIG_EXT2_FS=y
 # 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
 
@@ -443,6 +510,7 @@ 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
@@ -514,6 +582,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index b0fe571..0bd354d 100644 (file)
@@ -1,5 +1,7 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1-bk21
+# Fri Nov 12 16:08:53 2004
 #
 CONFIG_M32R=y
 CONFIG_UID16=y
@@ -12,10 +14,12 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_CLEAN_COMPILE is not set
 CONFIG_BROKEN=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
@@ -24,17 +28,20 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=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
+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
@@ -44,6 +51,7 @@ 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
 CONFIG_STOP_MACHINE=y
 
@@ -83,17 +91,6 @@ 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)
 #
@@ -101,11 +98,18 @@ CONFIG_M32R_NE2000=y
 # CONFIG_ISA is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_PCMCIA=y
+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_PCC=y
 
 #
 # PCI Hotplug Support
@@ -213,6 +217,16 @@ CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+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
@@ -231,7 +245,6 @@ 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
@@ -291,6 +304,9 @@ CONFIG_IP_PNP_DHCP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -310,7 +326,6 @@ CONFIG_IP_PNP_DHCP=y
 # 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
@@ -327,7 +342,48 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_NETDEVICES is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NE2000=y
+
+#
+# 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
@@ -365,6 +421,7 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -397,7 +454,6 @@ CONFIG_SERIAL_M32R_SIO_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -462,6 +518,8 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
@@ -481,6 +539,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -513,6 +572,7 @@ 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_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -558,6 +618,7 @@ 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
@@ -629,6 +690,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index b4ab5ff..a117915 100644 (file)
@@ -1,5 +1,7 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1-bk21
+# Fri Nov 12 16:08:55 2004
 #
 CONFIG_M32R=y
 CONFIG_UID16=y
@@ -12,10 +14,12 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_CLEAN_COMPILE is not set
 CONFIG_BROKEN=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
@@ -24,17 +28,20 @@ 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=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
+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
@@ -44,6 +51,7 @@ 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
 
 #
@@ -79,17 +87,6 @@ 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)
 #
@@ -97,11 +94,18 @@ CONFIG_M32R_NE2000=y
 # CONFIG_ISA is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_PCMCIA=y
+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_PCC=y
 
 #
 # PCI Hotplug Support
@@ -209,6 +213,16 @@ CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+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
@@ -227,7 +241,6 @@ 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
@@ -287,6 +300,9 @@ CONFIG_IP_PNP_DHCP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -306,7 +322,6 @@ CONFIG_IP_PNP_DHCP=y
 # 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
@@ -323,7 +338,48 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_NETDEVICES is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NE2000=y
+
+#
+# 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
@@ -361,6 +417,7 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
@@ -393,7 +450,6 @@ CONFIG_SERIAL_M32R_SIO_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -458,6 +514,8 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
@@ -477,6 +535,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -509,6 +568,7 @@ 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_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -554,6 +614,7 @@ 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
@@ -625,6 +686,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index ea566b6..7a1d293 100644 (file)
@@ -1,9 +1,9 @@
 # .gdbinit file
-# $Id$
+# $Id: dot.gdbinit.mappi,v 1.4 2004/10/20 02:24:37 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.8 2004/02/27 07:08:32 takata Exp $
+# $ Id: gen_gdbinit.pl,v 1.12 2004/07/26 09:56:10 takata Exp $
 #-----
 # target platform: mappi
 
@@ -192,11 +192,11 @@ end
 
 # Set kernel parameters
 define set_kernel_parameters
-  set $param = (void*)0x08002000
+  set $param = (void*)0x08001000
   # INITRD_START
-  set *(unsigned long *)($param + 0x0010) = 0x082a0000
+#  set *(unsigned long *)($param + 0x0010) = 0x08300000
   # INITRD_SIZE
-  set *(unsigned long *)($param + 0x0014) = 0x00000000
+#  set *(unsigned long *)($param + 0x0014) = 0x00000000
   # M32R_CPUCLK
   set *(unsigned long *)($param + 0x0018) = 0d360000000
   # M32R_BUSCLK
@@ -205,14 +205,14 @@ define set_kernel_parameters
   # 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"
+  set {char[0x200]}($param + 0x100) = "console=ttyS0,115200n8x console=tty1 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"
 end
 
 # Boot
 define boot
   set_kernel_parameters
   set $fp = 0
-  set $pc=0x08001000
+  set $pc = 0x08002000
   si
   c
 end
@@ -236,7 +236,7 @@ sdireset
 file vmlinux
 target m32rsdi
 setup
-#load_module
+#load_modules
 #set_breakpoints
 #boot
 
index 1ca03f8..297536c 100644 (file)
@@ -192,7 +192,7 @@ end
 
 # Set kernel parameters
 define set_kernel_parameters
-  set $param = (void*)0x00002000
+  set $param = (void*)0x00001000
   # INITRD_START
   #set *(unsigned long *)($param + 0x0010) = 0x082a0000
   # INITRD_SIZE
@@ -205,14 +205,14 @@ define set_kernel_parameters
   # 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"
+  set {char[0x200]}($param + 0x100) = "console=ttyS0,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 $pc=0x00002000
   set *(long *)0xfffffff4=0x8080
 #  b load_flat_binary
 #  set *(unsigned char *)0x08001003=0x63
index db0274f..171489a 100644 (file)
@@ -269,11 +269,11 @@ end
 
 # Set kernel parameters
 define set_kernel_parameters
-  set $param = (void*)0x08002000
+  set $param = (void*)0x08001000
   # INITRD_START
 # set *(unsigned long *)($param + 0x0010) = 0x082a0000
   # INITRD_SIZE
-  set *(unsigned long *)($param + 0x0014) = 0x00000000
+#  set *(unsigned long *)($param + 0x0014) = 0x00000000
   # M32R_CPUCLK
   set *(unsigned long *)($param + 0x0018) = 0d160000000
 #  set *(unsigned long *)($param + 0x0018) = 0d80000000
@@ -284,14 +284,14 @@ define set_kernel_parameters
   # 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 console=ttyS0,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 $pc=0x08002000
   set *(unsigned char *)0x08001003=0x03
   si
   c
@@ -309,7 +309,7 @@ define boot_mp
   set *(unsigned long *)0x00eff2f8 = 0x2
   x 0x00eff2f8
 
-  set $pc=0x08001000
+  set $pc=0x08002000
   si
   c
 end
@@ -320,7 +320,7 @@ end
 ## Boot UP
 define boot_up
   set_kernel_parameters
-  set $pc=0x08001000
+  set $pc=0x08002000
   si
   c
 end
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
+
+
index a290e37..b6a5aac 100644 (file)
@@ -18,9 +18,9 @@
 #include <linux/bootmem.h>
 #include <linux/swap.h>
 #include <linux/highmem.h>
+#include <linux/bitops.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>
index 816b53e..2239a9b 100644 (file)
@@ -1,5 +1,7 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1-bk21
+# Fri Nov 12 16:09:00 2004
 #
 CONFIG_M32R=y
 CONFIG_UID16=y
@@ -11,10 +13,12 @@ CONFIG_GENERIC_ISA_DMA=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 # CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
@@ -22,16 +26,19 @@ 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 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
+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
@@ -41,6 +48,7 @@ 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
 
 #
@@ -70,16 +78,6 @@ 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)
 #
@@ -87,9 +85,13 @@ CONFIG_M32R_NE2000=y
 # CONFIG_ISA is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
 #
-# CONFIG_PCMCIA is not set
 
 #
 # PCI Hotplug Support
@@ -138,6 +140,16 @@ 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
@@ -193,6 +205,9 @@ CONFIG_IP_PNP_DHCP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -212,7 +227,6 @@ CONFIG_IP_PNP_DHCP=y
 # 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
@@ -229,7 +243,43 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_NETDEVICES is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NE2000=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
 
 #
 # ISDN subsystem
@@ -264,6 +314,7 @@ 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
@@ -296,7 +347,6 @@ CONFIG_SERIAL_M32R_SIO_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -356,6 +406,8 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
@@ -375,6 +427,7 @@ CONFIG_EXT2_FS=y
 # 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
 
@@ -435,6 +488,7 @@ 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
@@ -506,6 +560,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index 48420f7..d481d97 100644 (file)
@@ -1,9 +1,9 @@
 # .gdbinit file
-# $Id: dot.gdbinit.oaks32r,v 1.2 2004/04/15 02:33:14 takata Exp $
+# $Id: dot.gdbinit.oaks32r,v 1.4 2004/10/20 02:24:37 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 $
+# $ Id: gen_gdbinit.pl,v 1.12 2004/07/26 09:56:10 takata Exp $
 #-----
 # target platform: oaks32r
 
@@ -103,11 +103,11 @@ end
 
 # Set kernel parameters
 define set_kernel_parameters
-  set $param = (void*)0x01002000
+  set $param = (void*)0x01001000
   # INITRD_START
-  set *(unsigned long *)($param + 0x0010) = 0x00000000
+#  set *(unsigned long *)($param + 0x0010) = 0x00000000
   # INITRD_SIZE
-  set *(unsigned long *)($param + 0x0014) = 0x00000000
+#  set *(unsigned long *)($param + 0x0014) = 0x00000000
   # M32R_CPUCLK
   set *(unsigned long *)($param + 0x0018) = 0d66666667
   # M32R_BUSCLK
@@ -116,15 +116,14 @@ define set_kernel_parameters
   # 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"
+  set {char[0x200]}($param + 0x100) = "console=ttyS0,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"
 end
 
 # Boot
 define boot
   set_kernel_parameters
   set $fp = 0
-  set $pc = 0x01001000
+  set $pc = 0x01002000
   si
   c
 end
index 07eae96..4c80a03 100644 (file)
@@ -1,5 +1,7 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1-bk21
+# Fri Nov 12 16:09:02 2004
 #
 CONFIG_M32R=y
 CONFIG_UID16=y
@@ -15,6 +17,7 @@ CONFIG_BROKEN_ON_SMP=y
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -24,17 +27,20 @@ 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_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
+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
@@ -44,6 +50,7 @@ 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
 
 #
@@ -76,18 +83,6 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # 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)
 #
@@ -95,11 +90,19 @@ CONFIG_M32700UT_DS1302=y
 # CONFIG_ISA is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-CONFIG_PCMCIA=y
+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=y
+CONFIG_M32R_CFC_NUM=1
 
 #
 # PCI Hotplug Support
@@ -147,6 +150,16 @@ CONFIG_BLK_DEV_LOOP=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
@@ -185,9 +198,8 @@ CONFIG_SCSI_MULTI_LUN=y
 #
 # 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_QLOGIC_1280_1040 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -243,6 +255,9 @@ CONFIG_IP_PNP_DHCP=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_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -262,7 +277,6 @@ CONFIG_IP_PNP_DHCP=y
 # 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
@@ -279,7 +293,50 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_NETDEVICES is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# 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
@@ -314,6 +371,7 @@ 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
@@ -340,13 +398,12 @@ CONFIG_SERIO_SERPORT=y
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_M32R_SIO is not set
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
 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
@@ -359,6 +416,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
+CONFIG_DS1302=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
@@ -411,6 +469,8 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # USB support
 #
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
 # USB Gadget Support
@@ -438,6 +498,7 @@ CONFIG_REISERFS_FS=m
 # 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
 
@@ -471,6 +532,7 @@ 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
 
@@ -505,6 +567,7 @@ 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
@@ -583,6 +646,7 @@ CONFIG_DEBUG_INFO=y
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index 9883f00..b7e6c66 100644 (file)
@@ -7,6 +7,39 @@ set radix 0d16
 set height 0
 debug_chaos
 
+# clk xin:cpu:bus=1:8:1
+define clock_init_on_181
+  set *(unsigned long *)0x00ef400c = 0x2
+  set *(unsigned long *)0x00ef4004 = 0x1
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4000 = 0x101
+end
+# clk xin:cpu:bus=1:8:2
+define clock_init_on_182
+  set *(unsigned long *)0x00ef400c = 0x1
+  set *(unsigned long *)0x00ef4004 = 0x1
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4000 = 0x101
+end
+
+# clk xin:cpu:bus=1:8:4
+define clock_init_on_184
+  set *(unsigned long *)0x00ef400c = 0x0
+  set *(unsigned long *)0x00ef4004 = 0x1
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4000 = 0x101
+end
+
+# clk xin:cpu:bus=1:1:1
+define clock_init_off
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4000 = 0x0
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4004 = 0x0
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef400c = 0x0
+end
+
 define tlb_init
   set $tlbbase = 0xfe000000
   set *(unsigned long *)($tlbbase + 0x04) = 0x0
@@ -83,7 +116,7 @@ end
 
 # Set kernel parameters
 define set_kernel_parameters
-  set $param = (void*)0x88002000
+  set $param = (void*)0x88001000
   # INITRD_START
 #  set *(unsigned long *)($param + 0x0010) = 0x08300000
   # INITRD_SIZE
@@ -97,7 +130,7 @@ define set_kernel_parameters
   # M32R_TIMER_DIVIDE
   set *(unsigned long *)($param + 0x0020) = 0d128
 
-  set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x\
+  set {char[0x200]}($param + 0x100) = "console=ttyS0,115200n8x console=tty1 \
   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 \
@@ -106,16 +139,11 @@ end
 
 define boot
   set_kernel_parameters
-  set $pc=0x88001000
+  set $pc=0x88002000
   set $fp=0
   set $evb=0x88000000
-  # I/D-Cache ON
-
-# IPI
-#  set *(long *)0x00eff2f8 = 0x2
-  set $fp=0
-#  set *(unsigned long *)0xa0ef4000 = 0x100
   si
+  c
 end
 
 # Show TLB entries
@@ -151,11 +179,29 @@ define show_regs
   printf "EVB[%08lx]\n",$evb
 end
 
+define restart
+  sdireset
+  sdireset
+  en 1
+  set $pc=0x0
+  c
+  tlb_init
+  setup
+  load_modules
+  boot
+end
+
 define setup
   debug_chaos
+# Clock
+#  shell sleep 0.1
+#  clock_init_off
+#  shell sleep 1
+#  clock_init_on_182
+#  shell sleep 0.1
+# SDRAM
   set *(unsigned long *)0xa0ef6004 = 0x0001053f
   set *(unsigned long *)0xa0ef6028 = 0x00031102
-#  set *(unsigned long *)0xa0ef400c = 0x2
 end
 
 sdireset
@@ -165,16 +211,8 @@ target m32rsdi
 set $pc=0x0
 b *0x30000
 c
+dis 1
 setup
 tlb_init
 load_modules
-#set *(long *)0xa0ef4000=0x101
-#set *(long *)0xa0ef400c=0x002
-
 boot
-#b tme_handler
-b *0x88000020
-
-
-
-
index 151726c..8888deb 100644 (file)
@@ -311,7 +311,7 @@ static void __init hades_fixup(int pci_modify)
         * Go through all devices, fixing up irqs as we see fit:
         */
 
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
        {
                if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
                {
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
index 31dcf1a..a0b854f 100644 (file)
  */
 
 #include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/kd.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/interrupt.h>
+#include <linux/module.h>
 #include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+
+#include <asm/bootinfo.h>
 #include <asm/machdep.h>
 #include <asm/blinken.h>
-#include <asm/hwtest.h>                           /* hwreg_present() */
+#include <asm/io.h>                               /* readb() and writeb() */
+#include <asm/hp300hw.h>
+#include <asm/rtc.h>
 
 #include "ints.h"
 #include "time.h"
 
+unsigned long hp300_model;
+unsigned long hp300_uart_scode = -1;
+unsigned char ledstate;
+
+static char s_hp330[] __initdata = "330";
+static char s_hp340[] __initdata = "340";
+static char s_hp345[] __initdata = "345";
+static char s_hp360[] __initdata = "360";
+static char s_hp370[] __initdata = "370";
+static char s_hp375[] __initdata = "375";
+static char s_hp380[] __initdata = "380";
+static char s_hp385[] __initdata = "385";
+static char s_hp400[] __initdata = "400";
+static char s_hp425t[] __initdata = "425t";
+static char s_hp425s[] __initdata = "425s";
+static char s_hp425e[] __initdata = "425e";
+static char s_hp433t[] __initdata = "433t";
+static char s_hp433s[] __initdata = "433s";
+static char *hp300_models[] __initdata = {
+       [HP_320]        = NULL,
+       [HP_330]        = s_hp330,
+       [HP_340]        = s_hp340,
+       [HP_345]        = s_hp345,
+       [HP_350]        = NULL,
+       [HP_360]        = s_hp360,
+       [HP_370]        = s_hp370,
+       [HP_375]        = s_hp375,
+       [HP_380]        = s_hp380,
+       [HP_385]        = s_hp385,
+       [HP_400]        = s_hp400,
+       [HP_425T]       = s_hp425t,
+       [HP_425S]       = s_hp425s,
+       [HP_425E]       = s_hp425e,
+       [HP_433T]       = s_hp433t,
+       [HP_433S]       = s_hp433s,
+};
+
+static char hp300_model_name[13] = "HP9000/";
+
 extern void hp300_reset(void);
 extern irqreturn_t (*hp300_default_handler[])(int, void *, struct pt_regs *);
 extern int show_hp300_interrupts(struct seq_file *, void *);
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+extern int hp300_setup_serial_console(void) __init;
+#endif
+
+int __init hp300_parse_bootinfo(const struct bi_record *record)
+{
+       int unknown = 0;
+       const unsigned long *data = record->data;
+
+       switch (record->tag) {
+       case BI_HP300_MODEL:
+               hp300_model = *data;
+               break;
+
+       case BI_HP300_UART_SCODE:
+               hp300_uart_scode = *data;
+               break;
+
+       case BI_HP300_UART_ADDR:
+               /* serial port address: ignored here */
+               break;
+
+        default:
+               unknown = 1;
+       }
+
+       return unknown;
+}
 
 #ifdef CONFIG_HEARTBEAT
 static void hp300_pulse(int x)
 {
-   if (x)
-      blinken_leds(0xfe);
-   else
-      blinken_leds(0xff);
+       if (x)
+               blinken_leds(0x10, 0);
+       else
+               blinken_leds(0, 0x10);
 }
 #endif
 
 static void hp300_get_model(char *model)
 {
-  strcpy(model, "HP9000/300");
+       strcpy(model, hp300_model_name);
+}
+
+#define RTCBASE                        0xf0420000
+#define RTC_DATA               0x1
+#define RTC_CMD                        0x3
+
+#define        RTC_BUSY                0x02
+#define        RTC_DATA_RDY            0x01
+
+#define rtc_busy()             (in_8(RTCBASE + RTC_CMD) & RTC_BUSY)
+#define rtc_data_available()   (in_8(RTCBASE + RTC_CMD) & RTC_DATA_RDY)
+#define rtc_status()           (in_8(RTCBASE + RTC_CMD))
+#define rtc_command(x)         out_8(RTCBASE + RTC_CMD, (x))
+#define rtc_read_data()                (in_8(RTCBASE + RTC_DATA))
+#define rtc_write_data(x)      out_8(RTCBASE + RTC_DATA, (x))
+
+#define RTC_SETREG     0xe0
+#define RTC_WRITEREG   0xc2
+#define RTC_READREG    0xc3
+
+#define RTC_REG_SEC2   0
+#define RTC_REG_SEC1   1
+#define RTC_REG_MIN2   2
+#define RTC_REG_MIN1   3
+#define RTC_REG_HOUR2  4
+#define RTC_REG_HOUR1  5
+#define RTC_REG_WDAY   6
+#define RTC_REG_DAY2   7
+#define RTC_REG_DAY1   8
+#define RTC_REG_MON2   9
+#define RTC_REG_MON1   10
+#define RTC_REG_YEAR2  11
+#define RTC_REG_YEAR1  12
+
+#define RTC_HOUR1_24HMODE 0x8
+
+#define RTC_STAT_MASK  0xf0
+#define RTC_STAT_RDY   0x40
+
+static inline unsigned char hp300_rtc_read(unsigned char reg)
+{
+       unsigned char s, ret;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       while (rtc_busy());
+       rtc_command(RTC_SETREG);
+       while (rtc_busy());
+       rtc_write_data(reg);
+       while (rtc_busy());
+       rtc_command(RTC_READREG);
+
+       do {
+               while (!rtc_data_available());
+               s = rtc_status();
+               ret = rtc_read_data();
+       } while ((s & RTC_STAT_MASK) != RTC_STAT_RDY);
+
+       local_irq_restore(flags);
+
+       return ret;
+}
+
+static inline unsigned char hp300_rtc_write(unsigned char reg,
+                                           unsigned char val)
+{
+       unsigned char s, ret;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       while (rtc_busy());
+       rtc_command(RTC_SETREG);
+       while (rtc_busy());
+       rtc_write_data((val << 4) | reg);
+       while (rtc_busy());
+       rtc_command(RTC_WRITEREG);
+       while (rtc_busy());
+       rtc_command(RTC_READREG);
+
+       do {
+               while (!rtc_data_available());
+               s = rtc_status();
+               ret = rtc_read_data();
+       } while ((s & RTC_STAT_MASK) != RTC_STAT_RDY);
+
+       local_irq_restore(flags);
+
+       return ret;
+}
+
+static int hp300_hwclk(int op, struct rtc_time *t)
+{
+       if (!op) { /* read */
+               t->tm_sec  = hp300_rtc_read(RTC_REG_SEC1) * 10 +
+                       hp300_rtc_read(RTC_REG_SEC2);
+               t->tm_min  = hp300_rtc_read(RTC_REG_MIN1) * 10 +
+                       hp300_rtc_read(RTC_REG_MIN2);
+               t->tm_hour = (hp300_rtc_read(RTC_REG_HOUR1) & 3) * 10 +
+                       hp300_rtc_read(RTC_REG_HOUR2);
+               t->tm_wday = -1;
+               t->tm_mday = hp300_rtc_read(RTC_REG_DAY1) * 10 +
+                       hp300_rtc_read(RTC_REG_DAY2);
+               t->tm_mon  = hp300_rtc_read(RTC_REG_MON1) * 10 +
+                       hp300_rtc_read(RTC_REG_MON2) - 1;
+               t->tm_year = hp300_rtc_read(RTC_REG_YEAR1) * 10 +
+                       hp300_rtc_read(RTC_REG_YEAR2);
+               if (t->tm_year <= 69)
+                       t->tm_year += 100;
+       } else {
+               hp300_rtc_write(RTC_REG_SEC1, t->tm_sec / 10);
+               hp300_rtc_write(RTC_REG_SEC2, t->tm_sec % 10);
+               hp300_rtc_write(RTC_REG_MIN1, t->tm_min / 10);
+               hp300_rtc_write(RTC_REG_MIN2, t->tm_min % 10);
+               hp300_rtc_write(RTC_REG_HOUR1,
+                               ((t->tm_hour / 10) & 3) | RTC_HOUR1_24HMODE);
+               hp300_rtc_write(RTC_REG_HOUR2, t->tm_hour % 10);
+               hp300_rtc_write(RTC_REG_DAY1, t->tm_mday / 10);
+               hp300_rtc_write(RTC_REG_DAY2, t->tm_mday % 10);
+               hp300_rtc_write(RTC_REG_MON1, (t->tm_mon + 1) / 10);
+               hp300_rtc_write(RTC_REG_MON2, (t->tm_mon + 1) % 10);
+               if (t->tm_year >= 100)
+                       t->tm_year -= 100;
+               hp300_rtc_write(RTC_REG_YEAR1, t->tm_year / 10);
+               hp300_rtc_write(RTC_REG_YEAR2, t->tm_year % 10);
+       }
+
+       return 0;
+}
+
+static unsigned int hp300_get_ss(void)
+{
+       return hp300_rtc_read(RTC_REG_SEC1) * 10 +
+               hp300_rtc_read(RTC_REG_SEC2);
 }
 
 void __init config_hp300(void)
 {
-  mach_sched_init      = hp300_sched_init;
-  mach_init_IRQ        = hp300_init_IRQ;
-  mach_request_irq     = hp300_request_irq;
-  mach_free_irq        = hp300_free_irq;
-  mach_get_model       = hp300_get_model;
-  mach_get_irq_list    = show_hp300_interrupts;
-  mach_gettimeoffset   = hp300_gettimeoffset;
-  mach_default_handler = &hp300_default_handler;
-  mach_reset           = hp300_reset;
+       mach_sched_init      = hp300_sched_init;
+       mach_init_IRQ        = hp300_init_IRQ;
+       mach_request_irq     = hp300_request_irq;
+       mach_free_irq        = hp300_free_irq;
+       mach_get_model       = hp300_get_model;
+       mach_get_irq_list    = show_hp300_interrupts;
+       mach_gettimeoffset   = hp300_gettimeoffset;
+       mach_default_handler = &hp300_default_handler;
+       mach_hwclk           = hp300_hwclk;
+       mach_get_ss          = hp300_get_ss;
+       mach_reset           = hp300_reset;
 #ifdef CONFIG_HEARTBEAT
-  mach_heartbeat       = hp300_pulse;
+       mach_heartbeat       = hp300_pulse;
 #endif
 #ifdef CONFIG_DUMMY_CONSOLE
-  conswitchp          = &dummy_con;
+       conswitchp           = &dummy_con;
+#endif
+       mach_max_dma_address = 0xffffffff;
+
+       if (hp300_model >= HP_330 && hp300_model <= HP_433S && hp300_model != HP_350) {
+               printk(KERN_INFO "Detected HP9000 model %s\n", hp300_models[hp300_model-HP_320]);
+               strcat(hp300_model_name, hp300_models[hp300_model-HP_320]);
+       }
+       else {
+               panic("Unknown HP9000 Model");
+       }
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+       hp300_setup_serial_console();
 #endif
-  mach_max_dma_address = 0xffffffff;
 }
index aaecdbd..52eb852 100644 (file)
 
        .globl  hp300_reset
 hp300_reset:
-       .chip   68030
-       oriw    #0x0700,%sr                     /* cli() */
-       movel   hp300_phys_ram_base, %d1
-       movel   #0, %d0
-       movec   %d0, %vbr                       /* reset vector table */
-       lea     zero, %a0
-       lea     1f, %a1
-       add     %d1, %a0
-       add     %d1, %a1
-       pmove   %tc, %a0@
-       bclr    #7, %a0@
-       pmove   %a0@, %tc                       /* goodbye MMU */
-       jmp     %a1@
-1:     movel   #0x808, %d0
-       movec   %d0, %cacr                      /* cache off */
-       moveb   #0, 0x1ffff
-       movel   #0x1a4, %a0
-       jmp     %a0@
-
-zero:  .quad   0
+       jmp     hp300_reset
index deb65b4..8da5b1b 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/traps.h>
+#include <asm/blinken.h>
 #include "ints.h"
 
 /* Clock hardware definitions */
 
 static irqreturn_t hp300_tick(int irq, void *dev_id, struct pt_regs *regs)
 {
-  unsigned long tmp;
-  irqreturn_t (*vector)(int, void *, struct pt_regs *) = dev_id;
-  in_8(CLOCKBASE + CLKSR);
-  asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
-  return vector(irq, NULL, regs);
+       unsigned long tmp;
+       irqreturn_t (*vector)(int, void *, struct pt_regs *) = dev_id;
+       in_8(CLOCKBASE + CLKSR);
+       asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
+       /* Turn off the network and SCSI leds */
+       blinken_leds(0, 0xe0);
+       return vector(irq, NULL, regs);
 }
 
 unsigned long hp300_gettimeoffset(void)
index 11d1229..e47e195 100644 (file)
@@ -45,6 +45,9 @@ static inline int set_rtc_mmss(unsigned long nowtime)
 static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
 {
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
        profile_tick(CPU_PROFILING, regs);
 
 #ifdef CONFIG_HEARTBEAT
index 48e85d1..497b924 100644 (file)
@@ -1,5 +1,9 @@
 #include <linux/config.h>
-
+PHDRS
+{
+  text PT_LOAD FILEHDR PHDRS FLAGS (7);
+  data PT_LOAD FLAGS (7);
+}
 #ifdef CONFIG_SUN3
 #include "vmlinux-sun3.lds"
 #else
index de3867d..4d4f069 100644 (file)
@@ -4,5 +4,4 @@
 
 obj-y  := sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o idprom.o
 
-obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o \
-                       intersil.o
+obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o intersil.o
index e6be8b7..2524de2 100644 (file)
@@ -15,8 +15,9 @@ platform-$(CONFIG_M68360)     := 68360
 platform-$(CONFIG_M5206)       := 5206
 platform-$(CONFIG_M5206e)      := 5206e
 platform-$(CONFIG_M5249)       := 5249
+platform-$(CONFIG_M527x)       := 527x
 platform-$(CONFIG_M5272)       := 5272
-platform-$(CONFIG_M5282)       := 5282
+platform-$(CONFIG_M528x)       := 528x
 platform-$(CONFIG_M5307)       := 5307
 platform-$(CONFIG_M5407)       := 5407
 PLATFORM := $(platform-y)
@@ -28,12 +29,16 @@ board-$(CONFIG_UCQUICC)             := uCquicc
 board-$(CONFIG_DRAGEN2)                := de2
 board-$(CONFIG_ARNEWSH)                := ARNEWSH
 board-$(CONFIG_MOTOROLA)       := MOTOROLA
+board-$(CONFIG_M5271EVB)       := M5271EVB
+board-$(CONFIG_M5275EVB)       := M5275EVB
+board-$(CONFIG_M5282EVB)       := M5282EVB
 board-$(CONFIG_ELITE)          := eLITE
 board-$(CONFIG_eLIA)           := eLIA
 board-$(CONFIG_NETtel)         := NETtel
 board-$(CONFIG_SECUREEDGEMP3)  := MP3
 board-$(CONFIG_CLEOPATRA)      := CLEOPATRA
-board-$(CONFIG_senTec)         := senTec
+board-$(CONFIG_senTec)         := senTec
+board-$(CONFIG_SNEHA)          := SNEHA
 BOARD := $(board-y)
 
 model-$(CONFIG_RAMKERNEL)      := ram
@@ -50,8 +55,9 @@ MODEL := $(model-y)
 cpuclass-$(CONFIG_M5206)       := 5307
 cpuclass-$(CONFIG_M5206e)      := 5307
 cpuclass-$(CONFIG_M5249)       := 5307
+cpuclass-$(CONFIG_M527x)       := 5307
 cpuclass-$(CONFIG_M5272)       := 5307
-cpuclass-$(CONFIG_M5282)       := 5307
+cpuclass-$(CONFIG_M528x)       := 5307
 cpuclass-$(CONFIG_M5407)       := 5307
 cpuclass-$(CONFIG_M68EZ328)    := 68328
 cpuclass-$(CONFIG_M68VZ328)    := 68328
@@ -69,8 +75,9 @@ export PLATFORM BOARD MODEL CPUCLASS
 cflags-$(CONFIG_M5206)         := -m5200 -Wa,-S -Wa,-m5200
 cflags-$(CONFIG_M5206e)                := -m5200 -Wa,-S -Wa,-m5200
 cflags-$(CONFIG_M5249)         := -m5200 -Wa,-S -Wa,-m5200
+cflags-$(CONFIG_M527x)         := -m5307 -Wa,-S -Wa,-m5307
 cflags-$(CONFIG_M5272)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M5282)         := -m5307 -Wa,-S -Wa,-m5307
+cflags-$(CONFIG_M528x)         := -m5307 -Wa,-S -Wa,-m5307
 cflags-$(CONFIG_M5307)         := -m5307 -Wa,-S -Wa,-m5307
 cflags-$(CONFIG_M5407)         := -m5200 -Wa,-S -Wa,-m5200
 cflags-$(CONFIG_M68328)                := -m68000
@@ -82,7 +89,7 @@ AFLAGS += $(cflags-y)
 
 CFLAGS += $(cflags-y)
 CFLAGS += -fno-builtin
-CFLAGS += -O2 -g
+CFLAGS += -O1 -g
 CFLAGS += -D__linux__
 CFLAGS += -DUTS_SYSNAME=\"uClinux\"
 
index b101057..e4bd31b 100644 (file)
@@ -35,8 +35,9 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_M5206 is not set
 # CONFIG_M5206e is not set
 # CONFIG_M5249 is not set
+# CONFIG_M527x is not set
 CONFIG_M5272=y
-# CONFIG_M5282 is not set
+# CONFIG_M528x is not set
 # CONFIG_M5307 is not set
 # CONFIG_M5407 is not set
 CONFIG_COLDFIRE=y
@@ -55,7 +56,10 @@ CONFIG_COLDFIRE=y
 # CONFIG_CLOCK_60MHz is not set
 CONFIG_CLOCK_66MHz=y
 # CONFIG_CLOCK_70MHz is not set
+# CONFIG_CLOCK_100MHz is not set
 # CONFIG_CLOCK_140MHz is not set
+# CONFIG_CLOCK_150MHz is not set
+# CONFIG_CLOCK_166MHz is not set
 
 #
 # Platform
index 8eb130e..3b1a2ff 100644 (file)
@@ -82,9 +82,38 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                       unsigned int relsec,
                       struct module *me)
 {
-       printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
-              me->name);
-       return -ENOEXEC;
+       unsigned int i;
+       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Sym *sym;
+       uint32_t *location;
+
+       DEBUGP("Applying relocate_add 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);
+
+               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               case R_68K_32:
+                       /* We add the value into the location given */
+                       *location = rel[i].r_addend + sym->st_value;
+                       break;
+               case R_68K_PC32:
+                       /* Add the value, subtract its postition */
+                       *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
+                       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 module_finalize(const Elf_Ehdr *hdr,
index 0d58915..c19722c 100644 (file)
@@ -745,147 +745,44 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
- *
- * Note that we go through the signals twice: once to check the signals
- * that the kernel can handle, and then we build all the user-level signal
- * handling stack-frames in one go after that.
  */
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
+       struct k_sigaction ka;
        siginfo_t info;
-       struct k_sigaction *ka;
-
-       current->thread.esp0 = (unsigned long) regs;
+       int signr;
+
+       /*
+        * 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 (!oldset)
                oldset = &current->blocked;
 
-       for (;;) {
-               int signr;
-
-               signr = get_signal_to_deliver(&info, regs, NULL);
-
-               if (!signr)
-                       break;
-
-               if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-                       current->exit_code = signr;
-                       current->state = TASK_STOPPED;
-                       regs->sr &= ~PS_T;
-
-                       /* Did we come from a system call? */
-                       if (regs->orig_d0 >= 0) {
-                               /* Restart the system call the same way as
-                                  if the process were not traced.  */
-                               struct k_sigaction *ka =
-                                       &current->sighand->action[signr-1];
-                               int has_handler =
-                                       (ka->sa.sa_handler != SIG_IGN &&
-                                        ka->sa.sa_handler != SIG_DFL);
-                               handle_restart(regs, ka, has_handler);
-                       }
-                       notify_parent(current, SIGCHLD);
-                       schedule();
-
-                       /* We're back.  Did the debugger cancel the sig?  */
-                       if (!(signr = current->exit_code)) {
-                       discard_frame:
-                           continue;
-                       }
-                       current->exit_code = 0;
-
-                       /* The debugger continued.  Ignore SIGSTOP.  */
-                       if (signr == SIGSTOP)
-                               goto discard_frame;
-
-                       /* Update the siginfo structure.  Is this good?  */
-                       if (signr != info.si_signo) {
-                               info.si_signo = signr;
-                               info.si_errno = 0;
-                               info.si_code = SI_USER;
-                               info.si_pid = current->parent->pid;
-                               info.si_uid = current->parent->uid;
-                       }
-
-                       /* If the (new) signal is now blocked, requeue it.  */
-                       if (sigismember(&current->blocked, signr)) {
-                               send_sig_info(signr, &info, current);
-                               continue;
-                       }
-               }
-
-               ka = &current->sighand->action[signr-1];
-               if (ka->sa.sa_handler == SIG_IGN) {
-                       if (signr != SIGCHLD)
-                               continue;
-                       /* Check for SIGCHLD: it's special.  */
-                       while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-                               /* nothing */;
-                       continue;
-               }
-
-               if (ka->sa.sa_handler == SIG_DFL) {
-                       int exit_code = signr;
-
-                       if (current->pid == 1)
-                               continue;
-
-                       switch (signr) {
-                       case SIGCONT: case SIGCHLD:
-                       case SIGWINCH: case SIGURG:
-                               continue;
-
-                       case SIGTSTP: case SIGTTIN: case SIGTTOU:
-                               if (is_orphaned_pgrp(process_group(current)))
-                                       continue;
-                               /* FALLTHRU */
-
-                       case SIGSTOP:
-                               current->state = TASK_STOPPED;
-                               current->exit_code = signr;
-                               if (!(current->parent->sighand->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-                                       notify_parent(current, SIGCHLD);
-                               schedule();
-                               continue;
-
-                       case SIGQUIT: case SIGILL: case SIGTRAP:
-                       case SIGIOT: case SIGFPE: case SIGSEGV:
-                       case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-                               if (do_coredump(signr, exit_code, regs))
-                                       exit_code |= 0x80;
-                               /* FALLTHRU */
-
-                       default:
-                               sigaddset(&current->pending.signal, signr);
-                               recalc_sigpending();
-                               current->flags |= PF_SIGNALED;
-                               do_exit(exit_code);
-                               /* NOTREACHED */
-                       }
-               }
-
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+       if (signr > 0) {
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, ka, &info, oldset, regs);
+               handle_signal(signr, &ka, &info, oldset, regs);
                return 1;
        }
 
        /* Did we come from a system call? */
-       if (regs->orig_d0 >= 0)
+       if (regs->orig_d0 >= 0) {
                /* Restart the system call - no handlers present */
-               handle_restart(regs, NULL, 0);
-
-       /* If we are about to discard some frame stuff we must copy
-          over the remaining frame. */
-       if (regs->stkadj) {
-               struct pt_regs *tregs =
-                 (struct pt_regs *) ((ulong) regs + regs->stkadj);
-
-               /* This must be copied with decreasing addresses to
-                  handle overlaps.  */
-               tregs->vector = 0;
-               tregs->format = 0;
-               tregs->pc = regs->pc;
-               tregs->sr = regs->sr;
+               if (regs->d0 == -ERESTARTNOHAND
+                   || regs->d0 == -ERESTARTSYS
+                   || regs->d0 == -ERESTARTNOINTR) {
+                       regs->d0 = regs->orig_d0;
+                       regs->pc -= 2;
+               } else if (regs->d0 == -ERESTART_RESTARTBLOCK) {
+                       regs->d0 = __NR_restart_syscall;
+                       regs->pc -= 2;
+               }
        }
        return 0;
 }
index 01a8c1d..897deaa 100644 (file)
@@ -185,7 +185,7 @@ ENTRY(sys_call_table)
        .long sys_ni_syscall    /* sys_mremap */
        .long sys_setresuid16
        .long sys_getresuid16   /* 165 */
-       .long sys_ni_syscall    /* for vm86 */
+       .long sys_getpagesize   /* sys_getpagesize */
        .long sys_ni_syscall    /* old "query_module" */
        .long sys_poll
        .long sys_ni_syscall    /* sys_nfsservctl */
@@ -237,42 +237,70 @@ ENTRY(sys_call_table)
        .long sys_setfsuid      /* 215 */
        .long sys_setfsgid
        .long sys_pivot_root
-       .long sys_ni_syscall    /* sys_mincore */
-       .long sys_ni_syscall    /* sys_madvise */
-       .long sys_getdents64    /* 220 */
-       .long sys_fcntl64
-       .long sys_ni_syscall    /* reserved for TUX */
        .long sys_ni_syscall
+       .long sys_ni_syscall
+       .long sys_getdents64    /* 220 */
        .long sys_gettid
-       .long sys_ni_syscall    /* 225 */ /* sys_readahead */
+       .long sys_tkill
        .long sys_setxattr
        .long sys_lsetxattr
-       .long sys_fsetxattr
+       .long sys_fsetxattr     /* 225 */
        .long sys_getxattr
-       .long sys_lgetxattr     /* 230 */
+       .long sys_lgetxattr
        .long sys_fgetxattr
        .long sys_listxattr
-       .long sys_llistxattr
+       .long sys_llistxattr    /* 230 */
        .long sys_flistxattr
-       .long sys_removexattr   /* 235 */
+       .long sys_removexattr
        .long sys_lremovexattr
        .long sys_fremovexattr
-       .long sys_tkill
+       .long sys_futex         /* 235 */
        .long sys_sendfile64
-       .long sys_futex         /* 240 */
-       .long sys_sched_setaffinity
-       .long sys_sched_getaffinity
-       .long sys_ni_syscall    /* sys_set_thread_area */
-       .long sys_ni_syscall    /* sys_get_thread_area */
-       .long sys_io_setup      /* 245 */
+       .long sys_ni_syscall    /* sys_mincore */
+       .long sys_ni_syscall    /* sys_madvise */
+       .long sys_fcntl64
+       .long sys_readahead     /* 240 */
+       .long sys_io_setup
        .long sys_io_destroy
        .long sys_io_getevents
        .long sys_io_submit
-       .long sys_io_cancel
-       .long sys_ni_syscall    /* 250 */ /* sys_alloc_hugepages */
-       .long sys_ni_syscall    /* sys_freec_hugepages */
+       .long sys_io_cancel     /* 245 */
+       .long sys_fadvise64
        .long sys_exit_group
        .long sys_lookup_dcookie
+       .long sys_epoll_create
+       .long sys_epoll_ctl     /* 250 */
+       .long sys_epoll_wait
+       .long sys_ni_syscall    /* sys_remap_file_pages */
+       .long sys_set_tid_address
+       .long sys_timer_create
+       .long sys_timer_settime /* 255 */
+       .long sys_timer_gettime
+       .long sys_timer_getoverrun
+       .long sys_timer_delete
+       .long sys_clock_settime
+       .long sys_clock_gettime /* 260 */
+       .long sys_clock_getres
+       .long sys_clock_nanosleep
+       .long sys_statfs64
+       .long sys_fstatfs64
+       .long sys_tgkill        /* 265 */
+       .long sys_utimes
+       .long sys_fadvise64_64
+       .long sys_mbind 
+       .long sys_get_mempolicy
+       .long sys_set_mempolicy /* 270 */
+       .long sys_mq_open
+       .long sys_mq_unlink
+       .long sys_mq_timedsend
+       .long sys_mq_timedreceive
+       .long sys_mq_notify     /* 275 */
+       .long sys_mq_getsetattr
+       .long sys_waitid
+       .long sys_ni_syscall    /* sys_setaltroot */
+       .long sys_ni_syscall    /* sys_add_key */
+       .long sys_ni_syscall    /* 280 */ /* sys_request_key */
+       .long sys_ni_syscall    /* sys_keyctl */
 
        .rept NR_syscalls-(.-sys_call_table)/4
                .long sys_ni_syscall
index e328f28..5c3ca67 100644 (file)
@@ -57,6 +57,9 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
        write_seqlock(&xtime_lock);
 
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
        if (current->pid)
                profile_tick(CPU_PROFILING, regs);
 
index 87f3bc4..8ba00a2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     vmlinux.lds.S -- master linker script for m68knommu arch
  *
- *     (C) Copyright 2002-2003, Greg Ungerer <gerg@snapgear.com>
+ *     (C) Copyright 2002-2004, Greg Ungerer <gerg@snapgear.com>
  *
  *     This ends up looking compilcated, because of the number of
  *     address variations for ram and rom/flash layouts. The real
  */
 #if defined(CONFIG_M5206eC3) || defined(CONFIG_M5249C3) || \
     defined(CONFIG_M5272C3) || defined(CONFIG_M5307C3) || \
-    defined(CONFIG_ARN5307) || defined(CONFIG_M5407C3)
+    defined(CONFIG_ARN5307) || defined(CONFIG_M5407C3) || \
+    defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB)
 #define        RAM_START       0x20000
 #define        RAM_LENGTH      0x3e0000
 #endif
 #define RAM_LENGTH  0xfe0000
 #endif
 
-#if defined(CONFIG_M5282C3)
+#if defined(CONFIG_M5282EVB)
 #define        RAM_START       0x10000
 #define        RAM_LENGTH      0x3f0000
 #endif
 
 /*
  *   The senTec COBRA5282 board has the same
- *   memory layout as the M5282C3.
+ *   memory layout as the M5282EVB.
  */
 #if defined(CONFIG_COBRA5282)
 #define  RAM_START   0x10000
  */
 #if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \
     defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \
-    defined(CONFIG_CLEOPATRA)
+    defined(CONFIG_HW_FEITH)
 #define        RAM_START       0x400
 #define        RAM_LENGTH      0x3ffc00
 #endif
 
+/*
+ *     Sneha Boards mimimun memmory
+ *     The end of RAM will vary depending on how much ram is fitted,
+ *     but this isn't important here, we assume at least 4MiB.
+ */
+#if defined(CONFIG_CPU16B)   
+#define        RAM_START       0x20000
+#define        RAM_LENGTH      0x3e0000
+#endif
+
+
 #if defined(CONFIG_RAMKERNEL)
 #define        TEXT            ram
 #define        DATA            ram
@@ -247,6 +259,11 @@ SECTIONS {
                /* Kernel symbol table: strings */
                *(__ksymtab_strings)
 
+               /* Built-in module parameters */
+               __start___param = .;
+               *(__param)
+               __stop___param = .;
+
                . = ALIGN(4) ;
                _etext = . ;
        } > TEXT
@@ -303,7 +320,7 @@ SECTIONS {
                __initramfs_start = .;
                *(.init.ramfs)
                __initramfs_end = .;
-               . = ALIGN(4);
+               . = ALIGN(4096);
                __init_end = .;
        } > INIT
 
index 0c734d9..e051a79 100644 (file)
@@ -4,4 +4,4 @@
 
 lib-y  := ashldi3.o ashrdi3.o lshrdi3.o \
           muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
-          checksum.o semaphore.o memcpy.o memset.o
+          checksum.o semaphore.o memcpy.o memset.o delay.o
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);
+}
+
index ce33f2f..748990d 100644 (file)
@@ -38,7 +38,6 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/machdep.h>
-#include <asm/shglcore.h>
 
 #undef DEBUG
 
index 9ec7dfe..0eef729 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/traps.h>
-#include <asm/shglcore.h>
 #include <asm/io.h>
 
 /*
index fdb9392..2049f44 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #define        MEM_BASE        0x00000000      /* Memory base at address 0 */
-#define        MEM_SIZE        0x00400000      /* Memory size 4Mb */
 #define        VBR_BASE        MEM_BASE        /* Vector address */
 
 /*****************************************************************************/
@@ -78,9 +77,36 @@ _start:
 
 
        /*
-        *      Set to 4 meg for the Cadre III board (m5206e).
+        *      SDRAM size for the Cadre III board (m5206e).
         */
+#if defined(CONFIG_RAMAUTO)
+       movea.l #0x00000000,%a0
+       move.l  MCF_MBAR+MCFSIM_DCMR0,%d0
+       and.l   #0x00fe0000, %d0
+       beq     noaddr1
+       add.l   #0x00020000,%d0
+       move.l  %d0,%a0
+noaddr1:
+       move.l  MCF_MBAR+MCFSIM_DCMR1,%d0
+       and.l   #0x00fe0000, %d0
+       beq     noaddr2
+       add.l   #0x00020000,%d0
+       add.l   %d0,%a0
+noaddr2:
+
+#else
+
+#if defined(CONFIG_RAM32MB)
+#define MEM_SIZE       0x02000000      /* Memory size 32Mb */
+#elif 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
        move.l  #MEM_SIZE, %a0
+#endif
 
        move.l  %a0, %d0                        /* Mem end addr is in a0 */
        move.l  %d0, %sp                        /* Set up initial stack ptr */
index cd7c904..f35b860 100644 (file)
@@ -22,7 +22,6 @@
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
 #include <asm/irq.h>
-#include <asm/delay.h>
 
 /***************************************************************************/
 
index a1bed39..289c182 100644 (file)
@@ -21,7 +21,6 @@
 #include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
-#include <asm/delay.h>
 
 /***************************************************************************/
 
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 */
+
+/*****************************************************************************/
index e325c19..a9e0dce 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
-#include <asm/delay.h>
 
 /***************************************************************************/
 
@@ -110,7 +109,7 @@ void config_BSP(char *commandp, int size)
 #if defined(CONFIG_BOOTPARAM)
        strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
        commandp[size-1] = 0;
-#elif defined(CONFIG_NETtel)
+#elif defined(CONFIG_NETtel) || defined(CONFIG_SCALES)
        /* Copy command line from FLASH to local buffer... */
        memcpy(commandp, (char *) 0xf0004000, size);
        commandp[size-1] = 0;
@@ -118,6 +117,10 @@ void config_BSP(char *commandp, int size)
        /* Copy command line from FLASH to local buffer... */
        memcpy(commandp, (char *) 0xffe06000, size);
        commandp[size-1] = 0;
+#elif defined(CONFIG_CANCam)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0xf0010000, size);
+       commandp[size-1] = 0;
 #else
        memset(commandp, 0, size);
 #endif
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 */
+
+/*****************************************************************************/
index 9959b83..3f54610 100644 (file)
@@ -20,8 +20,10 @@ obj-$(CONFIG_COLDFIRE)       += entry.o vectors.o ints.o
 obj-$(CONFIG_M5206)    += timers.o
 obj-$(CONFIG_M5206e)   += timers.o
 obj-$(CONFIG_M5249)    += timers.o
+obj-$(CONFIG_M527x)     += pit.o
 obj-$(CONFIG_M5272)    += timers.o
 obj-$(CONFIG_M5307)    += config.o timers.o
+obj-$(CONFIG_M528x)     += pit.o
 obj-$(CONFIG_M5407)    += timers.o
 
 ifeq ($(CONFIG_M5307),y)
index e816437..3f505da 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
-#include <asm/delay.h>
 #include <asm/mcfwdebug.h>
 
 /***************************************************************************/
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;  
+}
+
+/***************************************************************************/
index 1f882ca..ac313a1 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/unistd.h>
+#include <linux/delay.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
 #include <asm/traps.h>
@@ -22,7 +23,6 @@
 #include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
-#include <asm/delay.h>
 #include <asm/mcfwdebug.h>
 
 /***************************************************************************/
index ef76b15..f7c9018 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
-#include <asm/delay.h>
 
 /***************************************************************************/
 
index 4439d7f..0dd7a34 100644 (file)
@@ -45,7 +45,7 @@ static struct smatch mach_table[] = {
                MACH_SGI_IP28,
                PROM_FLAG_ARCS
        }, {    "SGI-IP32",
-               "SGI IP32",
+               "SGI O2",
                MACH_GROUP_SGI,
                MACH_SGI_IP32,
                PROM_FLAG_ARCS
index f34abfd..84867de 100644 (file)
@@ -104,5 +104,5 @@ ArcFlushAllCaches(VOID)
 
 DISPLAY_STATUS * __init ArcGetDisplayStatus(ULONG FileID)
 {
-       return ARC_CALL1(GetDisplayStatus, FileID);
+       return (DISPLAY_STATUS *) ARC_CALL1(GetDisplayStatus, FileID);
 }
index afac7ed..0b00df8 100644 (file)
@@ -39,8 +39,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
@@ -91,10 +91,10 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = {
 
 #elif defined(CONFIG_SOC_AU1500)
 
-       { AU1000_UART0_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1500_UART0_INT, INTC_INT_HIGH_LEVEL, 0},
        { AU1000_PCI_INTA, INTC_INT_LOW_LEVEL, 0 },
        { AU1000_PCI_INTB, INTC_INT_LOW_LEVEL, 0 },
-       { AU1000_UART3_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1500_UART3_INT, INTC_INT_HIGH_LEVEL, 0},
        { AU1000_PCI_INTC, INTC_INT_LOW_LEVEL, 0 },
        { AU1000_PCI_INTD, INTC_INT_LOW_LEVEL, 0 },
        { AU1000_DMA_INT_BASE, INTC_INT_HIGH_LEVEL, 0},
@@ -117,16 +117,16 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = {
        { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
        { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
        { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
-       { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
-       { AU1000_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1500_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1500_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
        { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
 
 #elif defined(CONFIG_SOC_AU1100)
 
-       { AU1000_UART0_INT, INTC_INT_HIGH_LEVEL, 0},
-       { AU1000_UART1_INT, INTC_INT_HIGH_LEVEL, 0},
-       { 2/*AU1000_SD_INT*/, INTC_INT_HIGH_LEVEL, 0},
-       { AU1000_UART3_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1100_UART0_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1100_UART1_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1100_SD_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1100_UART3_INT, INTC_INT_HIGH_LEVEL, 0},
        { AU1000_SSI0_INT, INTC_INT_HIGH_LEVEL, 0},
        { AU1000_SSI1_INT, INTC_INT_HIGH_LEVEL, 0},
        { AU1000_DMA_INT_BASE, INTC_INT_HIGH_LEVEL, 0},
@@ -151,9 +151,9 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = {
        { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
        { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
        { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
-       { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1100_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
        /*{ AU1000_GPIO215_208_INT, INTC_INT_HIGH_LEVEL, 0},*/
-       /*{ AU1000_LCD_INT, INTC_INT_HIGH_LEVEL, 0 },*/
+       { AU1100_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
        { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
 
 #elif defined(CONFIG_SOC_AU1550)
@@ -187,6 +187,32 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = {
        { AU1550_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
        { AU1550_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
 
+#elif defined(CONFIG_SOC_AU1200)
+
+       { AU1200_UART0_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1200_SWT_INT, INTC_INT_RISE_EDGE, 0 },
+       { AU1200_SD_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1200_DDMA_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1200_MAE_BE_INT, INTC_INT_HIGH_LEVEL, 0 },
+       { AU1200_UART1_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1200_MAE_FE_INT, INTC_INT_HIGH_LEVEL, 0 },
+       { AU1200_PSC0_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1200_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1200_AES_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1200_CAMERA_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1200_TOY_INT, INTC_INT_RISE_EDGE, 0 },
+       { AU1200_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+       { AU1200_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+       { AU1200_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
+       { AU1200_RTC_INT, INTC_INT_RISE_EDGE, 0 },
+       { AU1200_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+       { AU1200_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+       { AU1200_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
+       { AU1200_NAND_INT, INTC_INT_RISE_EDGE, 0},
+       { AU1200_USB_INT, INTC_INT_HIGH_LEVEL, 0 },
+       { AU1200_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
+       { AU1200_MAE_BOTH_INT, INTC_INT_HIGH_LEVEL, 0},
+
 #else
 #error "Error: Unknown Alchemy SOC"
 #endif
index 26744b3..84e6cf3 100644 (file)
@@ -39,6 +39,7 @@ struct cpu_spec       cpu_specs[] = {
     { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 },
     { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
     { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
+    { 0xffffffff, 0x04030200, "Au1200 AA", 0, 1 },
     { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
 };
 
index 9f6c61c..defdf5b 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/system.h>
 
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+
 /*
  * The Descriptor Based DMA supports up to 16 channels.
  *
@@ -63,6 +66,7 @@ static int dbdma_initialized;
 static void au1xxx_dbdma_init(void);
 
 typedef struct dbdma_device_table {
+       u32             dev_id;
        u32             dev_flags;
        u32             dev_tsize;
        u32             dev_devwidth;
@@ -89,64 +93,116 @@ typedef struct dbdma_chan_config {
 #define DEV_FLAGS_IN           (1 << 3)
 
 static dbdev_tab_t dbdev_tab[] = {
+#ifdef CONFIG_SOC_AU1550
        /* UARTS */
-       { DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 },
-       { DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 },
-       { DEV_FLAGS_OUT, 0, 8, 0x11400004, 0, 0 },
-       { DEV_FLAGS_IN, 0, 8, 0x11400000, 0, 0 },
+       { DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 },
+       { DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 },
+       { DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8, 0x11400004, 0, 0 },
+       { DSCR_CMD0_UART3_RX, DEV_FLAGS_IN, 0, 8, 0x11400000, 0, 0 },
 
        /* EXT DMA */
-       { 0, 0, 0, 0x00000000, 0, 0 },
-       { 0, 0, 0, 0x00000000, 0, 0 },
-       { 0, 0, 0, 0x00000000, 0, 0 },
-       { 0, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_DMA_REQ2, 0, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_DMA_REQ3, 0, 0, 0, 0x00000000, 0, 0 },
 
        /* USB DEV */
-       { DEV_FLAGS_IN, 4, 8, 0x10200000, 0, 0 },
-       { DEV_FLAGS_OUT, 4, 8, 0x10200004, 0, 0 },
-       { DEV_FLAGS_OUT, 4, 8, 0x10200008, 0, 0 },
-       { DEV_FLAGS_OUT, 4, 8, 0x1020000c, 0, 0 },
-       { DEV_FLAGS_IN, 4, 8, 0x10200010, 0, 0 },
-       { DEV_FLAGS_IN, 4, 8, 0x10200014, 0, 0 },
+       { DSCR_CMD0_USBDEV_RX0, DEV_FLAGS_IN, 4, 8, 0x10200000, 0, 0 },
+       { DSCR_CMD0_USBDEV_TX0, DEV_FLAGS_OUT, 4, 8, 0x10200004, 0, 0 },
+       { DSCR_CMD0_USBDEV_TX1, DEV_FLAGS_OUT, 4, 8, 0x10200008, 0, 0 },
+       { DSCR_CMD0_USBDEV_TX2, DEV_FLAGS_OUT, 4, 8, 0x1020000c, 0, 0 },
+       { DSCR_CMD0_USBDEV_RX3, DEV_FLAGS_IN, 4, 8, 0x10200010, 0, 0 },
+       { DSCR_CMD0_USBDEV_RX4, DEV_FLAGS_IN, 4, 8, 0x10200014, 0, 0 },
 
        /* PSC 0 */
-       { DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 },
-       { DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 },
+       { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 },
+       { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 },
 
        /* PSC 1 */
-       { DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 },
-       { DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 },
+       { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 },
+       { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 },
 
        /* PSC 2 */
-       { DEV_FLAGS_OUT, 0, 0, 0x10a0001c, 0, 0 },
-       { DEV_FLAGS_IN, 0, 0, 0x10a0001c, 0, 0 },
+       { DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT, 0, 0, 0x10a0001c, 0, 0 },
+       { DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN, 0, 0, 0x10a0001c, 0, 0 },
 
        /* PSC 3 */
-       { DEV_FLAGS_OUT, 0, 0, 0x10b0001c, 0, 0 },
-       { DEV_FLAGS_IN, 0, 0, 0x10b0001c, 0, 0 },
+       { DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT, 0, 0, 0x10b0001c, 0, 0 },
+       { DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN, 0, 0, 0x10b0001c, 0, 0 },
 
-       { 0, 0, 0, 0x00000000, 0, 0 },  /* PCI */
-       { 0, 0, 0, 0x00000000, 0, 0 },  /* NAND */
+       { DSCR_CMD0_PCI_WRITE, 0, 0, 0, 0x00000000, 0, 0 },     /* PCI */
+       { DSCR_CMD0_NAND_FLASH, 0, 0, 0, 0x00000000, 0, 0 },    /* NAND */
 
        /* MAC 0 */
-       { DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
-       { DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_MAC0_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_MAC0_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
 
        /* MAC 1 */
-       { DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
-       { DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_MAC1_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_MAC1_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
+
+#endif /* CONFIG_SOC_AU1550 */
+
+#ifdef CONFIG_SOC_AU1200
+       { DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 },
+       { DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 },
+       { DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8, 0x11200004, 0, 0 },
+       { DSCR_CMD0_UART1_RX, DEV_FLAGS_IN, 0, 8, 0x11200000, 0, 0 },
+
+       { DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 },
+
+       { DSCR_CMD0_MAE_BE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_MAE_FE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+       { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+
+       { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_AES_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+
+       { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 },
+       { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 },
+       { DSCR_CMD0_PSC0_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+       { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 },
+       { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 },
+       { DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+       { DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 
-       /* reserved */
-       { DEV_FLAGS_INUSE, 0, 0, 0x00000000, 0, 0 },
-       { DEV_FLAGS_INUSE, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
 
-       /* Memory */
-       { DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },   /* throttle */
-       { DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },   /* always */
+#endif // CONFIG_SOC_AU1200
+
+       { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 };
 
+#define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t))
+
 static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS];
 
+static dbdev_tab_t *
+find_dbdev_id (u32 id)
+{
+       int i;
+       dbdev_tab_t *p;
+       for (i = 0; i < DBDEV_TAB_SIZE; ++i) {
+               p = &dbdev_tab[i];
+               if (p->dev_id == id)
+                       return p;
+       }
+       return NULL;
+}
+
 /* Allocate a channel and return a non-zero descriptor if successful.
 */
 u32
@@ -172,8 +228,9 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
        if ((srcid > DSCR_NDEV_IDS) || (destid > DSCR_NDEV_IDS))
                return 0;
 
-       stp = &dbdev_tab[srcid];
-       dtp = &dbdev_tab[destid];
+       if ((stp = find_dbdev_id(srcid)) == NULL) return 0;
+       if ((dtp = find_dbdev_id(destid)) == NULL) return 0;
+
        used = 0;
        rv = 0;
 
@@ -212,7 +269,7 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
                                /* If kmalloc fails, it is caught below same
                                 * as a channel not available.
                                 */
-                               ctp = (chan_tab_t *)kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
+                               ctp = kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
                                chan_tab_ptr[i] = ctp;
                                ctp->chan_index = chan = i;
                                break;
@@ -313,7 +370,7 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
         * and if we try that first we are likely to not waste larger
         * slabs of memory.
         */
-       desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL);
+       desc_base = kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL);
        if (desc_base == 0)
                return 0;
 
@@ -324,7 +381,7 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
                kfree((const void *)desc_base);
                i = entries * sizeof(au1x_ddma_desc_t);
                i += (sizeof(au1x_ddma_desc_t) - 1);
-               if ((desc_base = (u32)kmalloc(i, GFP_KERNEL)) == 0)
+               if ((desc_base = kmalloc(i, GFP_KERNEL)) == 0)
                        return 0;
 
                desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t));
@@ -337,8 +394,8 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
 
        /* Initialize the rings with as much information as we know.
         */
-       srcid = stp - dbdev_tab;        /* Index is channel device ID */
-       destid = dtp - dbdev_tab;
+       srcid = stp->dev_id;
+       destid = dtp->dev_id;
 
        cmd0 = cmd1 = src1 = dest1 = 0;
        src0 = dest0 = 0;
@@ -691,7 +748,7 @@ au1xxx_dbdma_chan_free(u32 chanid)
        kfree(ctp);
 }
 
-static void
+static irqreturn_t
 dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        u32     intstat;
@@ -718,6 +775,7 @@ dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
 
+       return IRQ_HANDLED;
 }
 
 static void
@@ -773,3 +831,6 @@ au1xxx_dbdma_dump(u32 chanid)
                dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
        } while (dp != ctp->chan_desc_base);
 }
+
+#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
+
index f364091..0035a9b 100644 (file)
@@ -30,6 +30,7 @@
  *
  */
 
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -37,6 +38,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 #include <asm/system.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1000_dma.h>
@@ -71,6 +73,7 @@ struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = {
       {.dev_id = -1,},
       {.dev_id = -1,}
 };
+EXPORT_SYMBOL(au1000_dma_table);
 
 // Device FIFO addresses and default DMA modes
 static const struct dma_dev {
@@ -216,6 +219,7 @@ int request_au1000_dma(int dev_id, const char *dev_str,
 
        return i;
 }
+EXPORT_SYMBOL(request_au1000_dma);
 
 void free_au1000_dma(unsigned int dmanr)
 {
@@ -233,4 +237,6 @@ void free_au1000_dma(unsigned int dmanr)
        chan->irq_dev = NULL;
        chan->dev_id = -1;
 }
+EXPORT_SYMBOL(free_au1000_dma);
+
 #endif // AU1000 AU1500 AU1100
index 5104328..a19bb7e 100644 (file)
@@ -41,8 +41,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
 #define EXT_INTC1_REQ1 5 /* IP 5 */
 #define MIPS_TIMER_IP  7 /* IP 7 */
 
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-#endif
-
 extern asmlinkage void au1000_IRQ(void);
 extern void set_debug_traps(void);
 extern irq_cpustat_t irq_stat [NR_CPUS];
@@ -84,7 +80,6 @@ static inline void mask_and_ack_either_edge_irq(unsigned int irq_nr);
 inline void local_enable_irq(unsigned int irq_nr);
 inline void local_disable_irq(unsigned int irq_nr);
 
-extern void __init init_generic_irq(void);
 void   (*board_init_irq)(void);
 
 #ifdef CONFIG_PM
@@ -420,7 +415,7 @@ static void setup_local_irq(unsigned int irq_nr, int type, int int_req)
 }
 
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        int i;
        unsigned long cp0_status;
@@ -434,8 +429,6 @@ void __init init_IRQ(void)
        memset(irq_desc, 0, sizeof(irq_desc));
        set_except_vector(0, au1000_IRQ);
 
-       init_generic_irq();
-
        /* Initialize interrupt controllers to a safe state.
        */
        au_writel(0xffffffff, IC0_CFG0CLR);
@@ -482,13 +475,6 @@ void __init init_IRQ(void)
        */
        if (board_init_irq)
                (*board_init_irq)();
-
-#ifdef CONFIG_KGDB
-       /* If local serial I/O used for debug port, enter kgdb at once */
-       puts("Waiting for kgdb to connect...");
-       set_debug_traps();
-       breakpoint();
-#endif
 }
 
 
index d5ccbd2..7e187a0 100644 (file)
@@ -6,6 +6,8 @@
  * Author: MontaVista Software, Inc.
  *             ppopov@mvista.com or source@mvista.com
  *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
  *  Support for all devices (greater than 16) added by David Gathright.
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -35,7 +37,6 @@
 #include <linux/init.h>
 
 #include <asm/mach-au1x00/au1000.h>
-#include <asm/pci_channel.h>
 
 /* TBD */
 static struct resource pci_io_resource = {
@@ -67,15 +68,12 @@ static unsigned long virt_io_addr;
 static int __init au1x_pci_setup(void)
 {
 #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
-       int i;
-       struct pci_dev *dev;
-       
        virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START, 
                        Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1);
 
        if (!virt_io_addr) {
                printk(KERN_ERR "Unable to ioremap pci space\n");
-               return;
+               return 1;
        }
 
 #ifdef CONFIG_DMA_NONCOHERENT
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);
index 7d3a509..c2ae462 100644 (file)
@@ -92,7 +92,7 @@ puts(unsigned char *cp)
 }
 
 void
-fputs(unsigned char *cp)
+fputs(const char *cp)
 {
     unsigned char ch;
     int i = 0;
index 5bbc6cf..65b84db 100644 (file)
@@ -43,6 +43,7 @@ extern void (*flush_cache_all)(void);
 void au1000_restart(char *command)
 {
        /* Set all integrated peripherals to disabled states */
+       extern void board_reset (void);
        u32 prid = read_c0_prid();
 
        printk(KERN_NOTICE "\n** Resetting Integrated Peripherals\n");
@@ -154,18 +155,10 @@ void au1000_restart(char *command)
        flush_cache_all();
        write_c0_wired(0);
 
-#if defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500)
-       /* Do a HW reset if the board can do it */
-
-       au_writel(0x00000000, 0xAE00001C);
-#endif
-
-#if defined(CONFIG_MIPS_PB1550)
-        /* reset entire system */
-       au_writew(au_readw(0xAF00001C) & ~(1<<15), 0xAF00001C);
-       au_sync();
-#endif
+       /* Give board a chance to do a hardware reset */
+       board_reset();
 
+       /* Jump to the beggining in case board_reset() is empty */
        __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
 }
 
index a72de97..0d4dd7c 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/spinlock.h>
 #include <linux/hardirq.h>
 
+#include <asm/compiler.h>
 #include <asm/mipsregs.h>
 #include <asm/ptrace.h>
 #include <asm/time.h>
@@ -99,6 +100,9 @@ void mips_timer_interrupt(struct pt_regs *regs)
 
                kstat_this_cpu.irqs[irq]++;
                do_timer(regs);
+#ifndef CONFIG_SMP
+               update_process_times(user_mode(regs));
+#endif
                r4k_cur += r4k_offset;
                ack_r4ktimer(r4k_cur);
 
@@ -137,6 +141,9 @@ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
 
        while (time_elapsed > 0) {
                do_timer(regs);
+#ifndef CONFIG_SMP
+               update_process_times(user_mode(regs));
+#endif
                time_elapsed -= MATCH20_INC;
                last_match20 += MATCH20_INC;
                jiffie_drift++;
@@ -153,6 +160,9 @@ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
        if (jiffie_drift >= 999) {
                jiffie_drift -= 999;
                do_timer(regs); /* increment jiffies by one */
+#ifndef CONFIG_SMP
+               update_process_times(user_mode(regs));
+#endif
        }
 }
 
@@ -342,9 +352,9 @@ static unsigned long do_fast_cp0_gettimeoffset(void)
 
        __asm__("multu\t%1,%2\n\t"
                "mfhi\t%0"
-               :"=r" (res)
-               :"r" (count),
-                "r" (quotient));
+               : "=r" (res)
+               : "r" (count), "r" (quotient)
+               : "hi", "lo", GCC_REG_ACCUM);
 
        /*
         * Due to possible jiffies inconsistencies, we need to check 
index 21e2a91..a73a316 100644 (file)
@@ -61,8 +61,6 @@
 #define vdbg(fmt, arg...) do {} while (0)
 #endif
 
-#define MAX(a,b)       (((a)>(b))?(a):(b))
-
 #define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)
 
 #define EP_FIFO_DEPTH 8
@@ -211,9 +209,8 @@ dump_setup(struct usb_ctrlrequest* s)
 static inline usbdev_pkt_t *
 alloc_packet(endpoint_t * ep, int data_size, void* data)
 {
-       usbdev_pkt_t* pkt =
-               (usbdev_pkt_t *)kmalloc(sizeof(usbdev_pkt_t) + data_size,
-                                       ALLOC_FLAGS);
+       usbdev_pkt_t* pkt = kmalloc(sizeof(usbdev_pkt_t) + data_size,
+                                   ALLOC_FLAGS);
        if (!pkt)
                return NULL;
        pkt->ep_addr = ep->address;
index d7fbda4..5cb1166 100644 (file)
@@ -39,8 +39,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index 541837d..ac05ba0 100644 (file)
 /* not correct for db1550 */
 static BCSR * const bcsr = (BCSR *)0xAE000000;
 
+void board_reset (void)
+{
+       /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
+       au_writel(0x00000000, 0xAE00001C);
+}
+
 void __init board_setup(void)
 {
        u32 pin_func;
index cbae591..8f6ef0d 100644 (file)
@@ -40,8 +40,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index 585861e..58d41c2 100644 (file)
@@ -68,7 +68,7 @@ int wm97xx_comodule_present = 1;
 #define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
 #define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
-#define DPRINTK(format, arg...) printk(__FUNCTION__ ": " format "\n" , ## arg)
+#define DPRINTK(format, arg...) printk("%s: " format "\n", __FUNCTION__ , ## arg)
 
 
 #define PEN_DOWN_IRQ   AU1000_GPIO_7
index 84e1e41..904417a 100644 (file)
 
 extern struct rtc_ops no_rtc_ops;
 
+void board_reset (void)
+{
+}
+
 void __init board_setup(void)
 {
        u32 pin_func;
index a335c90..6eacaa0 100644 (file)
@@ -39,8 +39,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index 720bc75..51fcc2c 100644 (file)
@@ -39,8 +39,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index ab53e1a..0423786 100644 (file)
     !!! I shall not define symbols starting with CONFIG_ !!!
 #endif
 
+void board_reset (void)
+{
+}
+
 void __init board_setup(void)
 {
        u32 pin_func, static_cfg0;
index 215b07a..4950c33 100644 (file)
@@ -39,8 +39,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index abe5f47..e57c364 100644 (file)
@@ -37,8 +37,8 @@
 #include <asm/mipsregs.h>
 #include <asm/reboot.h>
 #include <asm/pgtable.h>
-#include <asm/au1000.h>
-#include <asm/pb1100.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-pb1x00/pb1100.h>
 
 #ifdef CONFIG_USB_OHCI
 // Enable the workaround for the OHCI DoneHead
     !!! I shall not define symbols starting with CONFIG_ !!!
 #endif
 
+void board_reset (void)
+{
+    /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
+    au_writel(0x00000000, 0xAE00001C);
+}
+
 void __init board_setup(void)
 {
        u32 pin_func;
index 6333deb..43be715 100644 (file)
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
 #include <asm/system.h>
-#include <asm/au1000.h>
+#include <asm/mach-au1x00/au1000.h>
 
 au1xxx_irq_map_t au1xxx_irq_map[] = {
        { AU1000_GPIO_9, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card Fully_Interted#
index 5b7ee00..9dd0106 100644 (file)
     !!! I shall not define symbols starting with CONFIG_ !!!
 #endif
 
+void board_reset (void)
+{
+    /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
+    au_writel(0x00000000, 0xAE00001C);
+}
+
 void __init board_setup(void)
 {
        u32 pin_func;
index 79c4e0f..476e250 100644 (file)
@@ -39,8 +39,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index 6cd5cc8..654fd31 100644 (file)
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-pb1x00/pb1550.h>
 
+void board_reset (void)
+{
+    /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
+       au_writew(au_readw(0xAF00001C) & ~(1<<15), 0xAF00001C);
+}
+
 void __init board_setup(void)
 {
        u32 pin_func;
index 4f69216..889d494 100644 (file)
@@ -39,8 +39,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index 3dcaef1..9dadc82 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/au1000.h>
 
+void board_reset (void)
+{
+       /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
+       au_writel(0x00000000, 0xAE00001C);
+}
+
 void __init board_setup(void)
 {
        u32 pin_func;
index d751f48..954800a 100644 (file)
@@ -39,8 +39,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index 38261f1..8b30333 100644 (file)
@@ -2,6 +2,8 @@
  * addinitrd - program to add a initrd image to an ecoff kernel
  *
  * (C) 1999 Thomas Bogendoerfer
+ * minor modifications, cleanup: Guido Guenther <agx@sigxcpu.org>
+ * further cleanup: Maciej W. Rozycki
  */
 
 #include <sys/types.h>
@@ -54,7 +56,7 @@ int main (int argc, char *argv[])
                exit (1);
        }
 
-       if ((fd_vmlinux = open (argv[1],O_RDWR)) < 0)
+       if ((fd_vmlinux = open (argv[1],O_RDONLY)) < 0)
                 die ("open vmlinux");
        if (read (fd_vmlinux, &efile, sizeof efile) != sizeof efile)
                die ("read file header");
@@ -78,6 +80,11 @@ int main (int argc, char *argv[])
                        swab = 1;
        }
 
+       /* make sure we have an empty data segment for the initrd */
+       if (eaout.dsize || esecs[1].s_size) {
+               fprintf (stderr, "Data segment not empty. Giving up!\n");
+               exit (1);
+       }
        if ((fd_initrd = open (argv[2], O_RDONLY)) < 0)
                die ("open initrd");
        if (fstat (fd_initrd, &st) < 0)
index ba46e8f..6d2a815 100644 (file)
@@ -87,7 +87,7 @@ asmlinkage void cobalt_irq(struct pt_regs *regs)
        }
 }
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        set_except_vector(0, cobalt_handle_int);
 
index 1c46106..6b4737e 100644 (file)
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 1997 by Ralf Baechle
+ * Copyright (C) 1996, 1997, 2004 by Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
  *
  */
@@ -15,7 +15,6 @@
 #include <linux/init.h>
 
 #include <asm/bootinfo.h>
-#include <asm/pci_channel.h>
 #include <asm/time.h>
 #include <asm/io.h>
 #include <asm/irq.h>
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
index a6e9337..231afaa 100644 (file)
@@ -1,5 +1,7 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc2
+# Sun Nov 21 14:12:04 2004
 #
 CONFIG_MIPS=y
 CONFIG_MIPS64=y
@@ -10,12 +12,12 @@ CONFIG_64BIT=y
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -24,17 +26,20 @@ CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=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
+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
@@ -59,6 +64,7 @@ CONFIG_IOSCHED_CFQ=y
 # CONFIG_MOMENCO_OCELOT is not set
 CONFIG_MOMENCO_OCELOT_G=y
 # 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
@@ -115,7 +121,6 @@ CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
 CONFIG_CPU_HAS_SYNC=y
 # CONFIG_PREEMPT is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 
 #
 # Bus options (PCI, PCMCIA, EISA, ISA, TC)
@@ -131,6 +136,7 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_BUILD_ELF64 is not set
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -144,6 +150,7 @@ CONFIG_BINFMT_ELF32=y
 #
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 
 #
@@ -172,6 +179,18 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # 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_CDROM_PKTCDVD=y
+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
@@ -228,10 +247,13 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
+CONFIG_XFRM_USER=y
 
 #
 # SCTP Configuration (EXPERIMENTAL)
@@ -249,7 +271,6 @@ CONFIG_XFRM=y
 # 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
@@ -372,6 +393,7 @@ CONFIG_SERIO=y
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_RAW=y
 
 #
 # Input Device Drivers
@@ -406,7 +428,6 @@ 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
@@ -426,7 +447,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # 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
@@ -436,6 +456,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # CONFIG_I2C is not set
 
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
 #
 # Misc devices
 #
@@ -458,7 +483,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 
 #
@@ -470,6 +494,8 @@ CONFIG_DUMMY_CONSOLE=y
 # USB support
 #
 # CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
 # USB Gadget Support
@@ -489,6 +515,7 @@ CONFIG_EXT2_FS=y
 # 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
 
@@ -501,7 +528,8 @@ CONFIG_EXT2_FS=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -549,6 +577,7 @@ CONFIG_LOCKD=y
 CONFIG_EXPORTFS=y
 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
@@ -569,13 +598,15 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Kernel hacking
 #
+# CONFIG_DEBUG_KERNEL is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
-# CONFIG_DEBUG_KERNEL is not set
 
 #
 # Security options
 #
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
 # CONFIG_SECURITY is not set
 
 #
@@ -586,6 +617,8 @@ CONFIG_CMDLINE=""
 #
 # Library routines
 #
-CONFIG_CRC16=y
+# CONFIG_CRC_CCITT is not set
 # CONFIG_CRC32 is not set
 # CONFIG_LIBCRC32C is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
index b2d4800..bc44e30 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the common code of NEC DDB-Vrc5xxx board
 #
 
-obj-y   += irq.o nile4.o prom.o rtc_ds1386.o
+obj-y   += nile4.o prom.o rtc_ds1386.o
index 7c99c81..68c127c 100644 (file)
@@ -222,7 +222,6 @@ static hw_irq_controller nile4_irq_controller = {
 void nile4_irq_setup(u32 base) {
 
        int i;
-       extern irq_desc_t irq_desc[];
 
        irq_base=base;
 
@@ -258,7 +257,6 @@ void nile4_irq_setup(u32 base) {
                irq_desc[i].depth = 1;
                irq_desc[i].handler = &nile4_irq_controller;
        }
-
 }
 
 #if defined(CONFIG_RUNTIME_DEBUG)
index d652aec..27f6a66 100644 (file)
 #include <asm/ddb5xxx/ddb5074.h>
 #include <asm/ddb5xxx/ddb5xxx.h>
 
-#ifdef CONFIG_KGDB
-extern void rs_kgdb_hook(int);
-extern void breakpoint(void);
-#endif
-
 static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000;
 
 static void ddb_machine_restart(char *command)
@@ -63,7 +58,6 @@ static void ddb_machine_power_off(void)
        } while (1);
 }
 
-extern void ddb_irq_setup(void);
 extern void rtc_ds1386_init(unsigned long base);
 
 extern void (*board_timer_setup) (struct irqaction * irq);
@@ -96,7 +90,6 @@ static void __init ddb5074_setup(void)
 {
        extern int panic_timeout;
 
-       irq_setup = ddb_irq_setup;
        set_io_port_base(NILE4_PCI_IO_BASE);
        isa_slot_offset = NILE4_PCI_MEM_BASE;
        board_timer_setup = ddb_timer_init;
index 2c53c7a..50b245d 100644 (file)
 #define TIMER_IRQ                      (VRC5476_IRQ_BASE + VRC5476_IRQ_GPT)
 #endif
 
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-#endif
-
 static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000;
 
 static void ddb_machine_restart(char *command)
@@ -70,7 +66,6 @@ static void ddb_machine_power_off(void)
        while (1);
 }
 
-extern void ddb_irq_setup(void);
 extern void rtc_ds1386_init(unsigned long base);
 
 static void __init ddb_time_init(void)
@@ -129,14 +124,11 @@ static struct {
 
 
 static void ddb5476_board_init(void);
-extern void ddb5476_irq_setup(void);
-extern void (*irq_setup)(void);
 
 static void __init ddb5476_setup(void)
 {
        extern int panic_timeout;
 
-       irq_setup = ddb5476_irq_setup;
        set_io_port_base(KSEG1ADDR(DDB_PCI_IO_BASE));
 
        board_time_init = ddb_time_init;
index c662dd2..a77682b 100644 (file)
@@ -66,15 +66,14 @@ static hw_irq_controller vrc5476_irq_controller = {
 void __init
 vrc5476_irq_init(u32 base)
 {
-       extern irq_desc_t irq_desc[];
        u32 i;
 
        irq_base = base;
        for (i= base; i< base + NUM_VRC5476_IRQ; i++) {
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
-                irq_desc[i].depth = 1;
-                irq_desc[i].handler = &vrc5476_irq_controller;
+               irq_desc[i].depth = 1;
+               irq_desc[i].handler = &vrc5476_irq_controller;
        }
 }
 
index ab8b838..0d5e706 100644 (file)
@@ -100,10 +100,8 @@ hw_irq_controller vrc5477_irq_controller = {
        NULL                    /* no affinity stuff for UP */
 };
 
-void
-vrc5477_irq_init(u32 irq_base)
+void __init vrc5477_irq_init(u32 irq_base)
 {
-       extern irq_desc_t irq_desc[];
        u32 i;
 
        for (i= irq_base; i< irq_base+ NUM_5477_IRQ; i++) {
index dc02a3a..97b1fcd 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright 2001 MontaVista Software Inc.
  * Author: jsun@mvista.com or jsun@junsun.net
  *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
  * arch/mips/ddb5xxx/ddb5477/setup.c
  *     Setup file for DDB5477.
  *
@@ -35,7 +37,6 @@
 #include <asm/gdb-stub.h>
 #include <asm/traps.h>
 #include <asm/debug.h>
-#include <asm/pci_channel.h>
 
 #include <asm/ddb5xxx/ddb5xxx.h>
 
@@ -165,8 +166,6 @@ static void __init ddb_timer_setup(struct irqaction *irq)
 }
 
 static void ddb5477_board_init(void);
-extern void ddb5477_irq_setup(void);
-extern void (*irq_setup)(void);
 
 extern struct pci_controller ddb5477_ext_controller;
 extern struct pci_controller ddb5477_io_controller;
@@ -178,7 +177,6 @@ static int  ddb5477_setup(void)
        /* initialize board - we don't trust the loader */
         ddb5477_board_init();
 
-       irq_setup = ddb5477_irq_setup;
        set_io_port_base(KSEG1ADDR(DDB_PCI_IO_BASE));
 
        board_time_init = ddb_time_init;
index f7e3dc3..23ec745 100644 (file)
@@ -26,7 +26,6 @@
 #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
 
 extern int _ftext, _end;               /* begin and end of kernel image */
-extern void *__rd_start, *__rd_end;    /* begin and end of ramdisk image */
 extern void kernel_entry(int, char **, unsigned long, int *);
 
 void * memcpy(void * dest, const void *src, unsigned int count)
@@ -81,11 +80,5 @@ void dec_entry(int argc, char **argv,
                rex_clear_cache();
        }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-       LOADER_TYPE = 1;
-       INITRD_START = (long)&__rd_start;
-       INITRD_SIZE = (long)&__rd_end - (long)&__rd_start;
-#endif
-
        kernel_entry(argc, argv, magic, prom_vec);
 }
index 83b079a..4b5279e 100644 (file)
@@ -48,11 +48,6 @@ extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs);
 
 extern asmlinkage void decstation_handle_int(void);
 
-#ifdef CONFIG_BLK_DEV_INITRD
-extern unsigned long initrd_start, initrd_end;
-extern void * __rd_start, * __rd_end;
-#endif
-
 spinlock_t ioasic_ssr_lock;
 
 volatile u32 *ioasic_base;
@@ -136,11 +131,6 @@ extern void dec_timer_setup(struct irqaction *);
 
 static void __init decstation_setup(void)
 {
-#ifdef CONFIG_BLK_DEV_INITRD
-       ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
-       initrd_start = (unsigned long)&__rd_start;
-       initrd_end = (unsigned long)&__rd_end;
-#endif
        board_be_init = dec_be_init;
        board_time_init = dec_time_init;
        board_timer_setup = dec_timer_setup;
@@ -701,7 +691,7 @@ void __init dec_init_kn03(void)
 }                              /* dec_init_kn03 */
 
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        switch (mips_machtype) {
        case MACH_DS23100:      /* DS2100/DS3100 Pmin/Pmax */
index 0e1ee11..97bf094 100644 (file)
@@ -59,9 +59,8 @@ asmlinkage void ev96100_cpu_irq(unsigned int pendin)
        do_IRQ(ffz8(pending >> 8), regs);
 }
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        set_except_vector(0, ev96100IRQ);
-       init_generic_irq();
        mips_cpu_irq_init(0);
 }
index 10189b9..8cbe842 100644 (file)
@@ -73,6 +73,9 @@ void mips_timer_interrupt(struct pt_regs *regs)
        do {
                kstat_this_cpu.irqs[irq]++;
                do_timer(regs);
+#ifndef CONFIG_SMP
+               update_process_times(user_mode(regs));
+#endif
                r4k_cur += r4k_offset;
                ack_r4ktimer(r4k_cur);
 
index 537eab3..9310135 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
@@ -128,7 +128,7 @@ void gt64120_irq_setup(void)
        set_c0_status(IE_IRQ2);
 }
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        int i;
 
index 3ef3584..8720bcc 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/config.h>
 
-#if defined(CONFIG_KGDB)
+#ifdef CONFIG_KGDB
 
 #include <asm/serial.h> /* For the serial port location and base baud */
 
index 6812277..1b56df4 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -51,7 +51,7 @@
 
 extern asmlinkage void ocelot_handle_int(void);
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        /*
         * Clear all of the interrupts while we change the able around a bit.
@@ -63,13 +63,6 @@ void __init init_IRQ(void)
        /* Sets the first-level interrupt dispatcher. */
        set_except_vector(0, ocelot_handle_int);
 
-       init_generic_irq();
        mips_cpu_irq_init(0);
        rm7k_cpu_irq_init(8);
-
-#ifdef CONFIG_KGDB
-       printk("start kgdb ...\n");
-       set_debug_traps();
-       breakpoint();   /* you may move this line to whereever you want :-) */
-#endif
 }
index 4be10d8..af8232e 100644 (file)
@@ -47,8 +47,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/serial_reg.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
 #define DPRINTK(fmt, args...)
 #endif
 
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-#endif
-
 /* revisit */
 #define EXT_IRQ0_TO_IP 2 /* IP 2 */
 #define EXT_IRQ5_TO_IP 7 /* IP 7 */
@@ -251,7 +247,7 @@ void enable_cpu_timer(void)
         local_irq_restore(flags);
 }
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        int i;
         unsigned long flags;
@@ -259,8 +255,6 @@ void __init init_IRQ(void)
         memset(irq_desc, 0, sizeof(irq_desc));
         set_except_vector(0, it8172_IRQ);
 
-       init_generic_irq();
-
        /* mask all interrupts */
        it8172_hw0_icregs->lb_mask  = 0xffff;
        it8172_hw0_icregs->lpc_mask = 0xffff;
@@ -297,13 +291,6 @@ void __init init_IRQ(void)
        }
        irq_desc[MIPS_CPU_TIMER_IRQ].handler = &cp0_irq_type;
        set_c0_status(ALLINTS_NOTIMER);
-
-#ifdef CONFIG_KGDB
-       /* If local serial I/O used for debug port, enter kgdb at once */
-       puts("Waiting for kgdb to connect...");
-       set_debug_traps();
-       breakpoint();
-#endif
 }
 
 void mips_spurious_interrupt(struct pt_regs *regs)
index e81e234..f714954 100644 (file)
@@ -19,11 +19,9 @@ extern asmlinkage void jazz_handle_int(void);
 
 static spinlock_t r4030_lock = SPIN_LOCK_UNLOCKED;
 
-extern asmlinkage void sni_rm200_pci_handle_int(void);
-
 static void enable_r4030_irq(unsigned int irq)
 {
-       unsigned int mask = 1 << (irq - JAZZ_IE_PARALLEL);
+       unsigned int mask = 1 << (irq - JAZZ_PARALLEL_IRQ);
        unsigned long flags;
 
        spin_lock_irqsave(&r4030_lock, flags);
@@ -42,7 +40,7 @@ static unsigned int startup_r4030_irq(unsigned int irq)
 
 void disable_r4030_irq(unsigned int irq)
 {
-       unsigned int mask = ~(1 << (irq - JAZZ_IE_PARALLEL));
+       unsigned int mask = ~(1 << (irq - JAZZ_PARALLEL_IRQ));
        unsigned long flags;
 
        spin_lock_irqsave(&r4030_lock, flags);
@@ -91,11 +89,10 @@ void __init init_r4030_ints(void)
  * driver compatibility reasons interrupts 0 - 15 to be the i8259
  * interrupts even if the hardware uses a different interrupt numbering.
  */
-void __init init_IRQ (void)
+void __init arch_init_irq(void)
 {
        set_except_vector(0, jazz_handle_int);
 
-       init_generic_irq();
        init_i8259_irqs();                      /* Integrated i8259  */
        init_r4030_ints();
 
index ceda294..79ac935 100644 (file)
@@ -304,6 +304,8 @@ unsigned long vdma_phys2log(unsigned long paddr)
        return (i << 12) + (paddr & (VDMA_PAGESIZE - 1));
 }
 
+EXPORT_SYMBOL(vdma_phys2log);
+
 /*
  * Translate a logical DMA address to a physical address
  */
@@ -394,6 +396,8 @@ void vdma_enable(int channel)
                          R4030_CHNL_ENABLE);
 }
 
+EXPORT_SYMBOL(vdma_enable);
+
 /*
  * Disable a DMA channel
  */
@@ -429,6 +433,8 @@ void vdma_disable(int channel)
        *((volatile unsigned int *) JAZZ_DUMMY_DEVICE);
 }
 
+EXPORT_SYMBOL(vdma_disable);
+
 /*
  * Set DMA mode. This function accepts the mode values used
  * to set a PC-style DMA controller. For the SCSI and FDC
@@ -496,6 +502,8 @@ void vdma_set_mode(int channel, int mode)
        }
 }
 
+EXPORT_SYMBOL(vdma_set_mode);
+
 /*
  * Set Transfer Address
  */
@@ -508,6 +516,8 @@ void vdma_set_addr(int channel, long addr)
        r4030_write_reg32(JAZZ_R4030_CHNL_ADDR + (channel << 5), addr);
 }
 
+EXPORT_SYMBOL(vdma_set_addr);
+
 /*
  * Set Transfer Count
  */
@@ -520,6 +530,8 @@ void vdma_set_count(int channel, int count)
        r4030_write_reg32(JAZZ_R4030_CHNL_COUNT + (channel << 5), count);
 }
 
+EXPORT_SYMBOL(vdma_set_count);
+
 /*
  * Get Residual
  */
index f7149c4..2a97547 100644 (file)
@@ -11,8 +11,6 @@
 #include <asm/reboot.h>
 #include <asm/delay.h>
 
-#define jazz_kh ((keyboard_hardware *) JAZZ_KEYBOARD_ADDRESS)
-
 #define KBD_STAT_IBF           0x02    /* Keyboard input buffer full */
 
 static void jazz_write_output(unsigned char val)
index 13ddc5c..b643127 100644 (file)
@@ -184,17 +184,12 @@ unsigned long jmr3927_do_gettimeoffset(void)
 }
 
 
-#if defined(CONFIG_BLK_DEV_INITRD)
-extern unsigned long __rd_start, __rd_end, initrd_start, initrd_end;
-#endif
-
 //#undef DO_WRITE_THROUGH
 #define DO_WRITE_THROUGH
 #define DO_ENABLE_CACHE
 
 extern char * __init prom_getcmdline(void);
 static void jmr3927_board_init(void);
-extern void jmr3927_irq_setup(void);
 extern struct resource pci_io_resource;
 extern struct resource pci_mem_resource;
 
@@ -203,7 +198,6 @@ static void __init jmr3927_setup(void)
        extern int panic_timeout;
        char *argptr;
 
-       irq_setup = jmr3927_irq_setup;
        set_io_port_base(JMR3927_PORT_BASE + JMR3927_PCIIO);
 
        board_time_init = jmr3927_time_init;
index 8b74e9c..2698893 100644 (file)
@@ -171,6 +171,8 @@ static int hexToLong(char **ptr, long *longValue);
 static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
 void handle_exception(struct gdb_regs *regs);
 
+int kgdb_enabled;
+
 /*
  * spin locks for smp case
  */
index b8b83bc..a5b0a38 100644 (file)
 #include <asm/stackframe.h>
 #include <asm/war.h>
 
+#define PANIC_PIC(msg)                                 \
+               .set push;                              \
+               .set    reorder;                        \
+               PTR_LA  a0,8f;                          \
+               .set    noat;                           \
+               PTR_LA  AT, panic;                      \
+               jr      AT;                             \
+9:             b       9b;                             \
+               .set    pop;                            \
+               TEXT(msg)
+
        __INIT
 
 NESTED(except_vec0_generic, 0, sp)
-       PANIC("Exception vector 0 called")
+       PANIC_PIC("Exception vector 0 called")
        END(except_vec0_generic)
 
 NESTED(except_vec1_generic, 0, sp)
-       PANIC("Exception vector 1 called")
+       PANIC_PIC("Exception vector 1 called")
        END(except_vec1_generic)
 
 /*
@@ -142,19 +153,17 @@ NESTED(except_vec_ejtag_debug, 0, sp)
 NESTED(ejtag_debug_handler, PT_SIZE, sp)
        .set    push
        .set    noat
-       .set    noreorder
        MTC0    k0, CP0_DESAVE
        mfc0    k0, CP0_DEBUG
 
        sll     k0, k0, 30      # Check for SDBBP.
        bgez    k0, ejtag_return
-       nop
 
        PTR_LA  k0, ejtag_debug_buffer
        LONG_S  k1, 0(k0)
        SAVE_ALL
+       move    a0, sp
        jal     ejtag_exception_handler
-        move   a0, sp
        RESTORE_ALL
        PTR_LA  k0, ejtag_debug_buffer
        LONG_L  k1, 0(k0)
@@ -163,7 +172,6 @@ ejtag_return:
        MFC0    k0, CP0_DESAVE
        .set    mips32
        deret
-        nop
        .set pop
        END(ejtag_debug_handler)
 
index 89a8456..a64e87d 100644 (file)
        .endm
 
        /*
-        * For the moment set ST0_KU so the CPU will not spit fire when
-        * executing 64-bit instructions.  The full initialization of the
-        * CPU's status register is done later in per_cpu_trap_init().
+        * For the moment disable interrupts, mark the kernel mode and
+        * set ST0_KX so that the CPU does not spit fire when using
+        * 64-bit addresses.  A full initialization of the CPU's status
+        * register is done later in per_cpu_trap_init().
         */
-       .macro  setup_c0_status
-#ifdef CONFIG_MIPS64
+       .macro  setup_c0_status set clr
+       .set    push
        mfc0    t0, CP0_STATUS
-       or      t0, ST0_KX
+       or      t0, ST0_CU0|\set|0x1f|\clr
+       xor     t0, 0x1f|\clr
        mtc0    t0, CP0_STATUS
+       .set    noreorder
+       sll     zero,3                          # ehb
+       .set    pop
+       .endm
+
+       .macro  setup_c0_status_pri
+#ifdef CONFIG_MIPS64
+       setup_c0_status ST0_KX 0
+#else
+       setup_c0_status 0 0
+#endif
+       .endm
+
+       .macro  setup_c0_status_sec
+#ifdef CONFIG_MIPS64
+       setup_c0_status ST0_KX ST0_BEV
+#else
+       setup_c0_status 0 ST0_BEV
 #endif
        .endm
 
@@ -114,7 +134,7 @@ EXPORT(_stext)
        __INIT
 
 NESTED(kernel_entry, 16, sp)                   # kernel entry point
-       setup_c0_status
+       setup_c0_status_pri
 
 #ifdef CONFIG_SGI_IP27
        GET_NASID_ASM   t1
@@ -124,8 +144,6 @@ NESTED(kernel_entry, 16, sp)                        # kernel entry point
 
        ARC64_TWIDDLE_PC
 
-       CLI                                     # disable interrupts
-
        PTR_LA          t0, __bss_start         # clear .bss
        LONG_S          zero, (t0)
        PTR_LA          t1, __bss_stop - LONGSIZE
@@ -144,7 +162,7 @@ NESTED(kernel_entry, 16, sp)                        # kernel entry point
        set_saved_sp    sp, t0, t1
        PTR_SUBU        sp, 4 * SZREG           # init stack pointer
 
-       jal             start_kernel
+       j               start_kernel
        END(kernel_entry)
 
 #ifdef CONFIG_SMP
@@ -153,6 +171,8 @@ NESTED(kernel_entry, 16, sp)                        # kernel entry point
  * function after setting up the stack and gp registers.
  */
 NESTED(smp_bootstrap, 16, sp)
+       setup_c0_status_sec
+
 #ifdef CONFIG_SGI_IP27
        GET_NASID_ASM   t1
        dli     t0, KLDIR_OFFSET + (KLI_KERN_VARS * KLDIR_ENT_SIZE) + \
@@ -166,9 +186,7 @@ NESTED(smp_bootstrap, 16, sp)
        ARC64_TWIDDLE_PC
 #endif /* CONFIG_SGI_IP27 */
 
-       CLI
-       setup_c0_status
-       jal     start_secondary
+       j       start_secondary
        END(smp_bootstrap)
 #endif /* CONFIG_SMP */
 
@@ -201,13 +219,3 @@ NESTED(smp_bootstrap, 16, sp)
        page    invalid_pmd_table, _PMD_ORDER
 #endif
        page    invalid_pte_table, _PTE_ORDER
-
-#ifdef CONFIG_MIPS64
-       /*
-        * 64-bit kernel mappings are really screwed up ...
-        */
-       page    kptbl, _PGD_ORDER
-       .globl  ekptbl
-       page    kpmdtbl, 0
-ekptbl:
-#endif
index 6fb136b..7eec756 100644 (file)
@@ -209,7 +209,7 @@ spurious_8259A_irq:
                 * lets ACK and report it. [once per IRQ]
                 */
                if (!(spurious_irq_mask & irqmask)) {
-                       printk("spurious 8259A interrupt: IRQ%d.\n", irq);
+                       printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
                        spurious_irq_mask |= irqmask;
                }
                atomic_inc(&irq_err_count);
@@ -295,7 +295,7 @@ void __init init_8259A(int auto_eoi)
  * IRQ2 is cascade interrupt to second interrupt controller
  */
 static struct irqaction irq2 = {
-       no_action, 0, 0, "cascade", NULL, NULL
+       no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL
 };
 
 static struct resource pic1_io_resource = {
index bc07d81..519cd5d 100644 (file)
@@ -47,6 +47,12 @@ COMPATIBLE_IOCTL(SBPROF_ZBSTOP)
 COMPATIBLE_IOCTL(SBPROF_ZBWAITFULL)
 #endif /* CONFIG_SIBYTE_TBPROF */
 
+/*HANDLE_IOCTL(RTC_IRQP_READ, w_long)
+COMPATIBLE_IOCTL(RTC_IRQP_SET)
+HANDLE_IOCTL(RTC_EPOCH_READ, w_long)
+COMPATIBLE_IOCTL(RTC_EPOCH_SET)
+*/
+
 IOCTL_TABLE_END
 
 int ioctl_table_size = ARRAY_SIZE(ioctl_start);
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 */
+
+}
index 9eb885d..1fc3b2e 100644 (file)
        and     t0, t0, t1
        LONG_S  t0, ST_OFF(t3)
 
-#ifdef CONFIG_MIPS32
-       fpu_save_double a0 t0                   # clobbers t0
-#endif
-#ifdef CONFIG_MIPS64
-       sll     t2, t0, 5
-       bgez    t2, 2f
-       sdc1    $f0, (THREAD_FPU + 0x00)(a0)
-        fpu_save_16odd a0
-2:
-        fpu_save_16even a0 t1                   # clobbers t1
-#endif
+       fpu_save_double a0 t1 t0 t2             # c0_status passed in t1
+                                               # clobbers t0 and t2
 1:
 
        /*
  * Save a thread's fp context.
  */
 LEAF(_save_fp)
-#ifdef CONFIG_MIPS32
-       fpu_save_double a0 t1                   # clobbers t1
-#endif
 #ifdef CONFIG_MIPS64
-       mfc0    t0, CP0_STATUS
-       sll     t1, t0, 5
-       bgez    t1, 1f                          # 16 register mode?
-       fpu_save_16odd a0
-1:
-       fpu_save_16even a0 t1                   # clobbers t1
-       sdc1    $f0, (THREAD_FPU + 0x00)(a0)
+       mfc0    t1, CP0_STATUS
 #endif
+       fpu_save_double a0 t1 t0 t2             # clobbers t1
        jr      ra
        END(_save_fp)
 
@@ -133,19 +116,7 @@ LEAF(_save_fp)
  * Restore a thread's fp context.
  */
 LEAF(_restore_fp)
-#ifdef CONFIG_MIPS32
        fpu_restore_double a0, t1               # clobbers t1
-#endif
-#ifdef CONFIG_MIPS64
-       mfc0    t0, CP0_STATUS
-       sll     t1, t0, 5
-       bgez    t1, 1f                          # 16 register mode?
-
-       fpu_restore_16odd a0
-1:     fpu_restore_16even a0, t0               # clobbers t0
-        ldc1   $f0, (THREAD_FPU + 0x00)(a0)
-#endif
-
        jr      ra
        END(_restore_fp)
 
index e70684e..f073841 100644 (file)
@@ -49,7 +49,7 @@ SECTIONS
 
   /* writeable */
   .data : {                    /* Data */
-    . = . + MAPPED_OFFSET;     /* for CONFIG_MAPPED_KERNEL */
+    . = . + DATAOFFSET;                /* for CONFIG_MAPPED_KERNEL */
     *(.data.init_task)
 
     *(.data)
@@ -85,8 +85,6 @@ SECTIONS
   /* will be freed after init */
   . = ALIGN(4096);             /* Init code and data */
   __init_begin = .;
-  /* /DISCARD/ doesn't work for .reginfo */
-  .reginfo : { *(.reginfo) }
   .init.text : {
        _sinittext = .;
        *(.init.text)
@@ -150,6 +148,14 @@ SECTIONS
         *(.exit.text)
         *(.exit.data)
         *(.exitcall.exit)
+
+       /* ABI crap starts here */
+       *(.comment)
+       *(.MIPS.options)
+       *(.note)
+       *(.options)
+       *(.pdr)
+       *(.reginfo)
   }
 
   /* This is the MIPS specific mdebug section.  */
index 0887134..1148a2d 100644 (file)
@@ -125,12 +125,10 @@ void lasat_hw0_irqdispatch(struct pt_regs *regs)
        }
 }
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        int i;
 
-       init_generic_irq();
-
        switch (mips_machtype) {
        case MACH_LASAT_100:
                lasat_int_status = (void *)LASAT_INT_STATUS_REG_100;
@@ -147,7 +145,7 @@ void __init init_IRQ(void)
                *lasat_int_mask &= 0xffff;
                break;
        default:
-               panic("init_IRQ: mips_machtype incorrect");
+               panic("arch_init_irq: mips_machtype incorrect");
        }
 
        /* Now safe to set the exception vector. */
index 0c21bb3..e371ed5 100644 (file)
@@ -134,7 +134,7 @@ void __init serial_init(void)
 
        memset(&s, 0, sizeof(s));
 
-       s.flags = STD_COM_FLAGS|UPF_RESOURCES;
+       s.flags = STD_COM_FLAGS;
        s.iotype = SERIAL_IO_MEM;
 
        if (mips_machtype == MACH_LASAT_100) {
index eb0b6cf..9f5752c 100644 (file)
@@ -190,7 +190,7 @@ unsigned int vtop(void *address)
        pgd = pgd_offset(current->mm, addr);
        pmd = pmd_offset(pgd, addr);
        pte = pte_offset(pmd, addr);
-       paddr = (KSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK;
+       paddr = (CKSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK;
        paddr |= (addr & ~PAGE_MASK);
 
        return paddr;
index 0d6dce9..2a2a0e0 100644 (file)
@@ -6,11 +6,12 @@
  * Copyright (C) 1994, 1995 Waldorf Electronics GmbH
  * Copyright (C) 1998, 1999 Ralf Baechle
  */
-#include <net/checksum.h>
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
 #include <asm/string.h>
 #include <asm/uaccess.h>
+#include <net/checksum.h>
 
 /*
  * copy while checksumming, otherwise like csum_partial
@@ -37,6 +38,7 @@ unsigned int csum_partial_copy_from_user (const char *src, char *dst,
 {
        int missing;
 
+       might_sleep();
        missing = copy_from_user(dst, src, len);
        if (missing) {
                memset(dst + len - missing, 0, missing);
index b8aad5f..e44e957 100644 (file)
@@ -28,7 +28,7 @@
  */
 
 #ifndef ATOMIC_DEC_AND_LOCK
-int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
        int counter;
        int newcount;
@@ -51,5 +51,5 @@ int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
        return 0;
 }
 
-EXPORT_SYMBOL(atomic_dec_and_lock);
+EXPORT_SYMBOL(_atomic_dec_and_lock);
 #endif /* ATOMIC_DEC_AND_LOCK */
index 6e92120..07660e8 100644 (file)
@@ -3,13 +3,12 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 1996, 1998, 1999 by Ralf Baechle
+ * Copyright (c) 1996, 1998, 1999, 2004 by Ralf Baechle
  * Copyright (c) 1999 Silicon Graphics, Inc.
  */
 #include <asm/asm.h>
 #include <asm/offset.h>
 #include <asm/regdef.h>
-#include <asm/sgidefs.h>
 
 #define EX(insn,reg,addr,handler)                      \
 9:     insn    reg, addr;                              \
index 0f31162..6e7a8ee 100644 (file)
@@ -3,13 +3,12 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 1996, 1998, 1999 by Ralf Baechle
+ * Copyright (c) 1996, 1998, 1999, 2004 by Ralf Baechle
  * Copyright (c) 1999 Silicon Graphics, Inc.
  */
 #include <asm/asm.h>
 #include <asm/offset.h>
 #include <asm/regdef.h>
-#include <asm/sgidefs.h>
 
 #define EX(insn,reg,addr,handler)                      \
 9:     insn    reg, addr;                              \
index f39b021..9b0abe9 100644 (file)
@@ -528,9 +528,9 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx)
                if (MIPSInst_FUNC(ir) != movc_op)
                        return SIGILL;
                cond = fpucondbit[MIPSInst_RT(ir) >> 2];
-               if (((ctx->fcr31 & cond) != 0) != ((MIPSInst_RT(ir) & 1) != 0))
-                       return 0;
-               xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)];
+               if (((ctx->fcr31 & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0))
+                       xcp->regs[MIPSInst_RD(ir)] =
+                               xcp->regs[MIPSInst_RS(ir)];
                break;
 #endif
 
index 1e832a6..de77f00 100644 (file)
@@ -118,12 +118,7 @@ void atlas_hw0_irqdispatch(struct pt_regs *regs)
        do_IRQ(irq, regs);
 }
 
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern int remote_debug;
-#endif
-
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        int i;
 
@@ -145,11 +140,4 @@ void __init init_IRQ(void)
                irq_desc[i].handler     = &atlas_irq_type;
                spin_lock_init(&irq_desc[i].lock);
        }
-
-#ifdef CONFIG_KGDB
-       if (remote_debug) {
-               set_debug_traps();
-               breakpoint();
-       }
-#endif
 }
index 3940bb8..0a1dd9b 100644 (file)
@@ -84,7 +84,7 @@ static void __init serial_init(void)
 #endif
        s.irq = ATLASINT_UART;
        s.uartclk = ATLAS_BASE_BAUD * 16;
-       s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | UPF_RESOURCES | ASYNC_AUTO_IRQ;
+       s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
        s.iotype = SERIAL_IO_PORT;
        s.regshift = 3;
 
index 636cdcd..31caf06 100644 (file)
@@ -42,8 +42,6 @@ extern char rs_getDebugChar(void);
 extern int saa9730_kgdb_hook(int);
 extern int saa9730_putDebugChar(char);
 extern char saa9730_getDebugChar(void);
-
-int remote_debug = 0;
 #endif
 
 int prom_argc;
@@ -219,7 +217,7 @@ void __init kgdb_config (void)
                                generic_putDebugChar (*s++);
                }
 
-               remote_debug = 1;
+               kgdb_enabled = 1;
                /* Breakpoint is invoked after interrupts are initialised */
        }
 }
index 56cf37a..5ae2b43 100644 (file)
@@ -77,7 +77,7 @@ struct prom_pmemblock * __init prom_getmdesc(void)
        mdesc[1].base = 0x00001000;
        mdesc[1].size = 0x000ef000;
 
-#if (CONFIG_MIPS_MALTA)
+#ifdef CONFIG_MIPS_MALTA
        /*
         * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
         * south bridge and PCI access always forwarded to the ISA Bus and
index cccd34c..92c34bd 100644 (file)
@@ -2,6 +2,8 @@
  * Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 1999, 2000 MIPS Technologies, Inc.  All rights reserved.
  *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
  *  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.
@@ -24,7 +26,6 @@
 #include <linux/init.h>
 
 #include <asm/mips-boards/generic.h>
-#include <asm/pci_channel.h>
 #include <asm/gt64120.h>
 #include <asm/mips-boards/bonito64.h>
 #include <asm/mips-boards/msc01_pci.h>
index 33e0f4b..92c3b66 100644 (file)
 
 extern asmlinkage void mipsIRQ(void);
 
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern void set_debug_traps(void);
-extern int remote_debug;
-#endif
-
 static spinlock_t mips_irq_lock = SPIN_LOCK_UNLOCKED;
 
 static inline int mips_pcibios_iack(void)
@@ -187,18 +181,8 @@ void corehi_irqdispatch(struct pt_regs *regs)
         die("CoreHi interrupt", regs);
 }
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        set_except_vector(0, mipsIRQ);
-       init_generic_irq();
        init_i8259_irqs();
-
-#ifdef CONFIG_KGDB
-       if (remote_debug) {
-               set_debug_traps();
-               breakpoint();
-       }
-#endif
 }
-
-
index 72a16bf..3377e66 100644 (file)
 #include <linux/pci.h>
 #include <linux/tty.h>
 
+#ifdef CONFIG_MTD
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#endif
+
 #include <asm/cpu.h>
 #include <asm/bootinfo.h>
 #include <asm/irq.h>
@@ -53,6 +60,30 @@ struct resource standard_io_resources[] = {
        { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
 };
 
+#ifdef CONFIG_MTD
+static struct mtd_partition malta_mtd_partitions[] = {
+       {
+               .name =         "YAMON",
+               .offset =       0x0,
+               .size =         0x100000,
+               .mask_flags =   MTD_WRITEABLE
+       },
+       {
+               .name =         "User FS",
+               .offset =       0x100000,
+               .size =         0x2e0000
+       },
+       {
+               .name =         "Board Config",
+               .offset =       0x3e0000,
+               .size =         0x020000,
+               .mask_flags =   MTD_WRITEABLE
+       }
+};
+
+#define number_partitions      (sizeof(malta_mtd_partitions)/sizeof(struct mtd_partition))
+#endif
+
 const char *get_system_type(void)
 {
        return "MIPS Malta";
@@ -132,13 +163,13 @@ static int __init malta_setup(void)
                        }
                }
                else
-                       panic ("Hardware DMA cache coherency not supported\n");
+                       panic("Hardware DMA cache coherency not supported");
 
 #endif
        }
 #ifdef CONFIG_DMA_COHERENT
        else {
-               panic ("Hardware DMA cache coherency not supported\n");
+               panic("Hardware DMA cache coherency not supported");
        }
 #endif
 
@@ -179,6 +210,15 @@ static int __init malta_setup(void)
        };
 #endif
 #endif
+
+#ifdef CONFIG_MTD
+       /*
+        * Support for MTD on Malta. Use the generic physmap driver
+        */
+       physmap_configure(0x1e000000, 0x400000, 4, NULL);
+       physmap_set_partitions(malta_mtd_partitions, number_partitions);
+#endif
+
        mips_reboot_setup();
 
        board_time_init = mips_time_init;
index 19fb7e2..e510965 100644 (file)
@@ -37,7 +37,7 @@ asmlinkage void sead_hw1_irqdispatch(struct pt_regs *regs)
        do_IRQ(SEADINT_UART1, regs);
 }
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
         /*
          * Mask out all interrupt
@@ -47,6 +47,5 @@ void __init init_IRQ(void)
        /* Now safe to set the exception vector. */
        set_except_vector(0, mipsIRQ);
 
-       init_generic_irq();
        mips_cpu_irq_init(0);
 }
index ab6c619..29892b8 100644 (file)
@@ -73,7 +73,7 @@ static void __init serial_init(void)
 #endif
        s.irq = SEADINT_UART0;
        s.uartclk = SEAD_BASE_BAUD * 16;
-       s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | UPF_RESOURCES | ASYNC_AUTO_IRQ;
+       s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
        s.iotype = 0;
        s.regshift = 3;
 
index 444df9c..887683b 100644 (file)
@@ -7,7 +7,7 @@
  * Tx39XX R4k style caches added. HK
  * Copyright (C) 1998, 1999, 2000 Harald Koerfgen
  * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
- * Copyright (C) 2001  Maciej W. Rozycki
+ * Copyright (C) 2001, 2004  Maciej W. Rozycki
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -337,6 +337,8 @@ void __init ld_mmu_r23000(void)
        flush_data_cache_page = r3k_flush_data_cache_page;
 
        _dma_cache_wback_inv = r3k_dma_cache_wback_inv;
+       _dma_cache_wback = r3k_dma_cache_wback_inv;
+       _dma_cache_inv = r3k_dma_cache_wback_inv;
 
        printk("Primary instruction cache %ldkB, linesize %ld bytes.\n",
                icache_size >> 10, icache_lsize);
index b22df2d..6249ac9 100644 (file)
@@ -49,7 +49,7 @@ struct bcache_ops *bcops = &no_sc_ops;
 #define R4600_HIT_CACHEOP_WAR_IMPL                                     \
 do {                                                                   \
        if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())            \
-               *(volatile unsigned long *)KSEG1;                       \
+               *(volatile unsigned long *)CKSEG1;                      \
        if (R4600_V1_HIT_CACHEOP_WAR)                                   \
                __asm__ __volatile__("nop;nop;nop;nop");                \
 } while (0)
@@ -86,7 +86,7 @@ static inline void r4k_blast_dcache_page_indexed_setup(void)
 
 static void (* r4k_blast_dcache)(void);
 
-static void r4k_blast_dcache_setup(void)
+static inline void r4k_blast_dcache_setup(void)
 {
        unsigned long dc_lsize = cpu_dcache_line_size();
 
@@ -254,16 +254,25 @@ static inline void r4k_blast_scache_setup(void)
                r4k_blast_scache = blast_scache128;
 }
 
+/*
+ * This is former mm's flush_cache_all() which really should be
+ * flush_cache_vunmap these days ...
+ */
+static inline void local_r4k_flush_cache_all(void * args)
+{
+       r4k_blast_dcache();
+       r4k_blast_icache();
+}
+
 static void r4k_flush_cache_all(void)
 {
        if (!cpu_has_dc_aliases)
                return;
 
-       r4k_blast_dcache();
-       r4k_blast_icache();
+       on_each_cpu(local_r4k_flush_cache_all, NULL, 1, 1);
 }
 
-static void r4k___flush_cache_all(void)
+static inline void local_r4k___flush_cache_all(void * args)
 {
        r4k_blast_dcache();
        r4k_blast_icache();
@@ -279,9 +288,14 @@ static void r4k___flush_cache_all(void)
        }
 }
 
-static void r4k_flush_cache_range(struct vm_area_struct *vma,
-       unsigned long start, unsigned long end)
+static void r4k___flush_cache_all(void)
 {
+       on_each_cpu(local_r4k___flush_cache_all, NULL, 1, 1);
+}
+
+static inline void local_r4k_flush_cache_range(void * args)
+{
+       struct vm_area_struct *vma = args;
        int exec;
 
        if (!(cpu_context(smp_processor_id(), vma->vm_mm)))
@@ -294,8 +308,16 @@ static void r4k_flush_cache_range(struct vm_area_struct *vma,
                r4k_blast_icache();
 }
 
-static void r4k_flush_cache_mm(struct mm_struct *mm)
+static void r4k_flush_cache_range(struct vm_area_struct *vma,
+       unsigned long start, unsigned long end)
 {
+       on_each_cpu(local_r4k_flush_cache_range, vma, 1, 1);
+}
+
+static inline void local_r4k_flush_cache_mm(void * args)
+{
+       struct mm_struct *mm = args;
+
        if (!cpu_has_dc_aliases)
                return;
 
@@ -316,9 +338,21 @@ static void r4k_flush_cache_mm(struct mm_struct *mm)
                r4k_blast_scache();
 }
 
-static void r4k_flush_cache_page(struct vm_area_struct *vma,
-                                       unsigned long page)
+static void r4k_flush_cache_mm(struct mm_struct *mm)
+{
+       on_each_cpu(local_r4k_flush_cache_mm, mm, 1, 1);
+}
+
+struct flush_cache_page_args {
+       struct vm_area_struct *vma;
+       unsigned long page;
+};
+
+static inline void local_r4k_flush_cache_page(void *args)
 {
+       struct flush_cache_page_args *fcp_args = args;
+       struct vm_area_struct *vma = fcp_args->vma;
+       unsigned long page = fcp_args->page;
        int exec = vma->vm_flags & VM_EXEC;
        struct mm_struct *mm = vma->vm_mm;
        pgd_t *pgdp;
@@ -377,14 +411,39 @@ static void r4k_flush_cache_page(struct vm_area_struct *vma,
        }
 }
 
+static void r4k_flush_cache_page(struct vm_area_struct *vma,
+       unsigned long page)
+{
+       struct flush_cache_page_args args;
+
+       args.vma = vma;
+       args.page = page;
+
+       on_each_cpu(local_r4k_flush_cache_page, &args, 1, 1);
+}
+
+static inline void local_r4k_flush_data_cache_page(void * addr)
+{
+       r4k_blast_dcache_page((unsigned long) addr);
+}
+
 static void r4k_flush_data_cache_page(unsigned long addr)
 {
-       r4k_blast_dcache_page(addr);
+       on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr, 1, 1);
 }
 
-static void r4k_flush_icache_range(unsigned long start, unsigned long end)
+struct flush_icache_range_args {
+       unsigned long start;
+       unsigned long end;
+};
+
+static inline void local_r4k_flush_icache_range(void *args)
 {
+       struct flush_icache_range_args *fir_args = args;
        unsigned long dc_lsize = current_cpu_data.dcache.linesz;
+       unsigned long ic_lsize = current_cpu_data.icache.linesz;
+       unsigned long start = fir_args->start;
+       unsigned long end = fir_args->end;
        unsigned long addr, aend;
 
        if (!cpu_has_ic_fills_f_dc) {
@@ -407,18 +466,28 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end)
        if (end - start > icache_size)
                r4k_blast_icache();
        else {
-               addr = start & ~(dc_lsize - 1);
-               aend = (end - 1) & ~(dc_lsize - 1);
+               addr = start & ~(ic_lsize - 1);
+               aend = (end - 1) & ~(ic_lsize - 1);
                while (1) {
                        /* Hit_Invalidate_I */
                        protected_flush_icache_line(addr);
                        if (addr == aend)
                                break;
-                       addr += dc_lsize;
+                       addr += ic_lsize;
                }
        }
 }
 
+static void r4k_flush_icache_range(unsigned long start, unsigned long end)
+{
+       struct flush_icache_range_args args;
+
+       args.start = start;
+       args.end = end;
+
+       on_each_cpu(local_r4k_flush_icache_range, &args, 1, 1);
+}
+
 /*
  * Ok, this seriously sucks.  We use them to flush a user page but don't
  * know the virtual address, so we have to blast away the whole icache
@@ -426,14 +495,17 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end)
  * least know the kernel address of the page so we can flush it
  * selectivly.
  */
-static void r4k_flush_icache_page(struct vm_area_struct *vma, struct page *page)
+
+struct flush_icache_page_args {
+       struct vm_area_struct *vma;
+       struct page *page;
+};
+
+static inline void local_r4k_flush_icache_page(void *args)
 {
-       /*
-        * If there's no context yet, or the page isn't executable, no icache
-        * flush is needed.
-        */
-       if (!(vma->vm_flags & VM_EXEC))
-               return;
+       struct flush_icache_page_args *fip_args = args;
+       struct vm_area_struct *vma = fip_args->vma;
+       struct page *page = fip_args->page;
 
        /*
         * Tricky ...  Because we don't know the virtual address we've got the
@@ -471,6 +543,25 @@ static void r4k_flush_icache_page(struct vm_area_struct *vma, struct page *page)
                r4k_blast_icache();
 }
 
+static void r4k_flush_icache_page(struct vm_area_struct *vma,
+       struct page *page)
+{
+       struct flush_icache_page_args args;
+
+       /*
+        * If there's no context yet, or the page isn't executable, no I-cache
+        * flush is needed.
+        */
+       if (!(vma->vm_flags & VM_EXEC))
+               return;
+
+       args.vma = vma;
+       args.page = page;
+
+       on_each_cpu(local_r4k_flush_icache_page, &args, 1, 1);
+}
+
+
 #ifdef CONFIG_DMA_NONCOHERENT
 
 static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
@@ -574,10 +665,11 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
  * very much about what happens in that case.  Usually a segmentation
  * fault will dump the process later on anyway ...
  */
-static void r4k_flush_cache_sigtramp(unsigned long addr)
+static void local_r4k_flush_cache_sigtramp(void * arg)
 {
        unsigned long ic_lsize = current_cpu_data.icache.linesz;
        unsigned long dc_lsize = current_cpu_data.dcache.linesz;
+       unsigned long addr = (unsigned long) arg;
 
        R4600_HIT_CACHEOP_WAR_IMPL;
        protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
@@ -587,10 +679,10 @@ static void r4k_flush_cache_sigtramp(unsigned long addr)
                        ".set push\n\t"
                        ".set noat\n\t"
                        ".set mips3\n\t"
-#if CONFIG_MIPS32
+#ifdef CONFIG_MIPS32
                        "la     $at,1f\n\t"
 #endif
-#if CONFIG_MIPS64
+#ifdef CONFIG_MIPS64
                        "dla    $at,1f\n\t"
 #endif
                        "cache  %0,($at)\n\t"
@@ -604,6 +696,11 @@ static void r4k_flush_cache_sigtramp(unsigned long addr)
                __asm__ __volatile__ ("sync");
 }
 
+static void r4k_flush_cache_sigtramp(unsigned long addr)
+{
+       on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr, 1, 1);
+}
+
 static void r4k_flush_icache_all(void)
 {
        if (cpu_has_vtag_icache)
@@ -893,7 +990,7 @@ static void __init probe_pcache(void)
               cpu_has_vtag_icache ? "virtually tagged" : "physically tagged",
               way_string[c->icache.ways], c->icache.linesz);
 
-       printk("Primary data cache %ldkB %s, linesize %d bytes.\n",
+       printk("Primary data cache %ldkB, %s, linesize %d bytes.\n",
               dcache_size >> 10, way_string[c->dcache.ways], c->dcache.linesz);
 }
 
@@ -982,7 +1079,7 @@ static void __init setup_scache(void)
        case CPU_R4000MC:
        case CPU_R4400SC:
        case CPU_R4400MC:
-               probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache));
+               probe_scache_kseg1 = (probe_func_t) (CKSEG1ADDR(&probe_scache));
                sc_present = probe_scache_kseg1(config);
                if (sc_present)
                        c->options |= MIPS_CPU_CACHE_CDEX_S;
index 5bae2b0..c90b412 100644 (file)
  */
 #include <linux/config.h>
 #include <linux/init.h>
-#include <asm/mmu_context.h>
+
+#include <asm/asm.h>
 #include <asm/bootinfo.h>
 #include <asm/cacheops.h>
 #include <asm/cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/mmu_context.h>
 #include <asm/uaccess.h>
 
 extern void sb1_dma_init(void);
@@ -32,17 +35,17 @@ extern void sb1_dma_init(void);
 static unsigned long icache_size;
 static unsigned long dcache_size;
 
-static unsigned long icache_line_size;
-static unsigned long dcache_line_size;
+static unsigned short icache_line_size;
+static unsigned short dcache_line_size;
 
 static unsigned int icache_index_mask;
 static unsigned int dcache_index_mask;
 
-static unsigned long icache_assoc;
-static unsigned long dcache_assoc;
+static unsigned short icache_assoc;
+static unsigned short dcache_assoc;
 
-static unsigned int icache_sets;
-static unsigned int dcache_sets;
+static unsigned short icache_sets;
+static unsigned short dcache_sets;
 
 static unsigned int icache_range_cutoff;
 static unsigned int dcache_range_cutoff;
@@ -449,6 +452,11 @@ static unsigned int decode_cache_line_size(unsigned int config_field)
  * 9:7   Dcache Associativity
  */
 
+static char *way_string[] = {
+       "direct mapped", "2-way", "3-way", "4-way",
+       "5-way", "6-way", "7-way", "8-way",
+};
+
 static __init void probe_cache_sizes(void)
 {
        u32 config1;
@@ -473,6 +481,13 @@ static __init void probe_cache_sizes(void)
         */
        icache_range_cutoff = icache_sets * icache_line_size;
        dcache_range_cutoff = (dcache_sets / 2) * icache_line_size;
+
+       printk("Primary instruction cache %ldkB, %s, linesize %d bytes.\n",
+              icache_size >> 10, way_string[icache_assoc - 1],
+              icache_line_size);
+       printk("Primary data cache %ldkB, %s, linesize %d bytes.\n",
+              dcache_size >> 10, way_string[dcache_assoc - 1],
+              dcache_line_size);
 }
 
 /*
@@ -526,15 +541,14 @@ void ld_mmu_sb1(void)
         * before subsequent instruction fetch.
         */
        __asm__ __volatile__(
+               ".set   push                    \n"
        "       .set    noat                    \n"
        "       .set    noreorder               \n"
-       "       .set    mips3\n\t               \n"
-       "       la      $1, 1f                  \n"
-       "       mtc0    $1, $14                 \n"
+       "       .set    mips3                   \n"
+       "       " STR(PTR_LA) " $1, 1f          \n"
+       "       " STR(MTC0) "   $1, $14         \n"
        "       eret                            \n"
-       "1:     .set    mips0\n\t               \n"
-       "       .set    at                      \n"
-       "       .set    reorder"
+       "1:     .set    pop"
        :
        :
        : "memory");
index 9654d74..9b0592d 100644 (file)
@@ -484,9 +484,9 @@ void __init ld_mmu_tx39(void)
        current_cpu_data.icache.waybit = 0;
        current_cpu_data.dcache.waybit = 0;
 
-       printk("Primary instruction cache %ldkb, linesize %d bytes\n",
+       printk("Primary instruction cache %ldkB, linesize %d bytes\n",
                icache_size >> 10, current_cpu_data.icache.linesz);
-       printk("Primary data cache %ldkb, linesize %d bytes\n",
+       printk("Primary data cache %ldkB, linesize %d bytes\n",
                dcache_size >> 10, current_cpu_data.dcache.linesz);
 
        build_clear_page();
index b95b91b..adf3522 100644 (file)
@@ -96,6 +96,15 @@ static int remap_area_pages(unsigned long address, phys_t phys_addr,
        return error;
 }
 
+/*
+ * Allow physical addresses to be fixed up to help 36 bit peripherals.
+ */
+phys_t __attribute__ ((weak))
+fixup_bigphys_addr(phys_t phys_addr, phys_t size)
+{
+       return phys_addr;
+}
+
 /*
  * Generic mapping function (not visible outside):
  */
@@ -110,7 +119,7 @@ static int remap_area_pages(unsigned long address, phys_t phys_addr,
  * caller shouldn't need to know that small detail.
  */
 
-#define IS_LOW512(addr) (!((phys_t)(addr) & ~0x1fffffffUL))
+#define IS_LOW512(addr) (!((phys_t)(addr) & (phys_t) ~0x1fffffffULL))
 
 void * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
 {
@@ -119,6 +128,8 @@ void * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
        phys_t last_addr;
        void * addr;
 
+       phys_addr = fixup_bigphys_addr(phys_addr, size);
+
        /* Don't allow wraparound or zero size */
        last_addr = phys_addr + size - 1;
        if (!size || last_addr < phys_addr)
@@ -171,15 +182,14 @@ void * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
 
 #define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1)
 
-void __iounmap(void *addr)
+void __iounmap(volatile void __iomem *addr)
 {
        struct vm_struct *p;
 
        if (IS_KSEG1(addr))
                return;
 
-       vfree((void *) (PAGE_MASK & (unsigned long) addr));
-       p = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
+       p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
        if (!p) {
                printk(KERN_ERR "iounmap: bad address %p\n", addr);
                return;
index 467fdfe..a26bf82 100644 (file)
@@ -224,7 +224,7 @@ static inline void build_cdex_p(void)
        emit_instruction(mi);
 }
 
-static void __build_store_reg(int reg)
+static void __init __build_store_reg(int reg)
 {
        union mips_instruction mi;
        unsigned int width;
@@ -356,7 +356,7 @@ void __init build_clear_page(void)
                case CPU_R10000:
                case CPU_R12000:
                        pref_src_mode = Pref_LoadStreamed;
-                       pref_dst_mode = Pref_StoreRetained;
+                       pref_dst_mode = Pref_StoreStreamed;
                        break;
 
                default:
index 7eb9533..e4b961c 100644 (file)
@@ -52,29 +52,8 @@ void pmd_init(unsigned long addr, unsigned long pagetable)
 
 void __init pagetable_init(void)
 {
-       pmd_t *pmd;
-       pte_t *pte;
-       int i;
-
        /* Initialize the entire pgd.  */
        pgd_init((unsigned long)swapper_pg_dir);
        pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table);
        memset((void *)invalid_pte_table, 0, sizeof(pte_t) * PTRS_PER_PTE);
-
-       memset((void *)kptbl, 0, PAGE_SIZE << PGD_ORDER);
-       memset((void *)kpmdtbl, 0, PAGE_SIZE);
-       set_pgd(swapper_pg_dir, __pgd((unsigned long)kpmdtbl));
-
-       /*
-        * The 64-bit kernel uses a flat pagetable for it's kernel mappings ...
-        */
-       pmd = kpmdtbl;
-       pte = kptbl;
-       i = 0;
-       while (i < (1 << PGD_ORDER)) {
-               pmd_val(*pmd) = (unsigned long)pte;
-               pte += PTRS_PER_PTE;
-               pmd++;
-               i++;
-       }
 }
index e1090c5..94ab754 100644 (file)
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 
-extern void except_vec0_generic(void);
-extern void except_vec0_r4000(void);
-extern void except_vec1_generic(void);
-extern void except_vec1_r10k(void);
+extern void build_tlb_refill_handler(void);
 
 #define NTLB_ENTRIES       64
 #define NTLB_ENTRIES_HALF  32
@@ -88,7 +85,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                                idx = read_c0_index();
                                write_c0_entrylo0(0);
                                write_c0_entrylo1(0);
-                               write_c0_entryhi(KSEG0);
+                               write_c0_entryhi(CKSEG0);
                                if(idx < 0)
                                        continue;
                                tlb_write_indexed();
@@ -126,7 +123,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
                        idx = read_c0_index();
                        write_c0_entrylo0(0);
                        write_c0_entrylo1(0);
-                       write_c0_entryhi(KSEG0 + (idx << (PAGE_SHIFT+1)));
+                       write_c0_entryhi(CKSEG0 + (idx << (PAGE_SHIFT+1)));
                        if (idx < 0)
                                continue;
                        tlb_write_indexed();
@@ -154,7 +151,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
                idx = read_c0_index();
                write_c0_entrylo0(0);
                write_c0_entrylo1(0);
-               write_c0_entryhi(KSEG0);
+               write_c0_entryhi(CKSEG0);
                if (idx < 0)
                        goto finish;
                tlb_write_indexed();
@@ -184,7 +181,7 @@ void local_flush_tlb_one(unsigned long page)
        write_c0_entrylo1(0);
        if (idx >= 0) {
                /* Make sure all entries differ. */
-               write_c0_entryhi(KSEG0+(idx<<(PAGE_SHIFT+1)));
+               write_c0_entryhi(CKSEG0+(idx<<(PAGE_SHIFT+1)));
                tlb_write_indexed();
        }
        write_c0_entryhi(oldpid);
@@ -257,14 +254,5 @@ void __init tlb_init(void)
 
        /* Did I tell you that ARC SUCKS?  */
 
-#ifdef CONFIG_MIPS32
-       memcpy((void *)KSEG0, &except_vec0_r4000, 0x80);
-       memcpy((void *)(KSEG0 + 0x080), &except_vec1_generic, 0x80);
-       flush_icache_range(KSEG0, KSEG0 + 0x100);
-#endif
-#ifdef CONFIG_MIPS64
-       memcpy((void *)(CKSEG0 + 0x000), &except_vec0_generic, 0x80);
-       memcpy((void *)(CKSEG0 + 0x080), except_vec1_r10k, 0x80);
-       flush_icache_range(CKSEG0 + 0x80, CKSEG0 + 0x100);
-#endif
+       build_tlb_refill_handler();
 }
index 89a0ee3..7948e9a 100644 (file)
@@ -26,7 +26,7 @@
 
 #undef DEBUG_TLB
 
-extern char except_vec0_r2300;
+extern void build_tlb_refill_handler(void);
 
 /* CP0 hazard avoidance. */
 #define BARRIER                                \
@@ -284,6 +284,6 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
 void __init tlb_init(void)
 {
        local_flush_tlb_all();
-       memcpy((void *)KSEG0, &except_vec0_r2300, 0x80);
-       flush_icache_range(KSEG0, KSEG0 + 0x80);
+
+       build_tlb_refill_handler();
 }
index 91fee06..59d38bc 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
-extern void except_vec0_generic(void);
-extern void except_vec0_nevada(void);
-extern void except_vec0_r4000(void);
-extern void except_vec0_r4600(void);
-extern void except_vec1_generic(void);
-extern void except_vec1_r4k(void);
+extern void build_tlb_refill_handler(void);
 
 /* CP0 hazard avoidance. */
 #define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
@@ -255,8 +250,14 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
        idx = read_c0_index();
        ptep = pte_offset_map(pmdp, address);
 
-       write_c0_entrylo0(pte_val(*ptep++) >> 6);
-       write_c0_entrylo1(pte_val(*ptep) >> 6);
+ #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+       write_c0_entrylo0(ptep->pte_high);
+       ptep++;
+       write_c0_entrylo1(ptep->pte_high);
+#else
+       write_c0_entrylo0(pte_val(*ptep++) >> 6);
+       write_c0_entrylo1(pte_val(*ptep) >> 6);
+#endif
        write_c0_entryhi(address | pid);
        mtc0_tlbw_hazard();
        if (idx < 0)
@@ -414,19 +415,5 @@ void __init tlb_init(void)
        temp_tlb_entry = current_cpu_data.tlbsize - 1;
        local_flush_tlb_all();
 
-#ifdef CONFIG_MIPS32
-       if (current_cpu_data.cputype == CPU_NEVADA)
-               memcpy((void *)KSEG0, &except_vec0_nevada, 0x80);
-       else if (current_cpu_data.cputype == CPU_R4600)
-               memcpy((void *)KSEG0, &except_vec0_r4600, 0x80);
-       else
-               memcpy((void *)KSEG0, &except_vec0_r4000, 0x80);
-       memcpy((void *)(KSEG0 + 0x080), &except_vec1_generic, 0x80);
-       flush_icache_range(KSEG0, KSEG0 + 0x100);
-#endif
-#ifdef CONFIG_MIPS64
-       memcpy((void *)(CKSEG0 + 0x00), &except_vec0_generic, 0x80);
-       memcpy((void *)(CKSEG0 + 0x80), except_vec1_r4k, 0x80);
-       flush_icache_range(CKSEG0 + 0x80, CKSEG0 + 0x100);
-#endif
+       build_tlb_refill_handler();
 }
index daac80e..1bfb091 100644 (file)
@@ -19,8 +19,7 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
-extern void except_vec0_generic(void);
-extern void except_vec1_r8k(void);
+extern void build_tlb_refill_handler(void);
 
 #define TFP_TLB_SIZE           384
 #define TFP_TLB_SET_SHIFT      7
@@ -247,7 +246,5 @@ void __init tlb_init(void)
 
        local_flush_tlb_all();
 
-       memcpy((void *)(CKSEG0 + 0x00), &except_vec0_generic, 0x80);
-       memcpy((void *)(CKSEG0 + 0x80), except_vec1_r8k, 0x80);
-       flush_icache_range(CKSEG0 + 0x80, CKSEG0 + 0x100);
+       build_tlb_refill_handler();
 }
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)
+
index cc4a464..04c11f1 100644 (file)
 
 #define TLB_OPTIMIZE /* If you are paranoid, disable this. */
 
-       .text
-       .set    mips1
-       .set    noreorder
-
-       __INIT
-
-       /* TLB refill, R[23]00 version */
-       LEAF(except_vec0_r2300)
-       .set    noat
-       .set    mips1
-       mfc0    k0, CP0_BADVADDR
-       lw      k1, pgd_current                 # get pgd pointer
-       srl     k0, k0, 22
-       sll     k0, k0, 2
-       addu    k1, k1, k0
-       mfc0    k0, CP0_CONTEXT
-       lw      k1, (k1)
-       and     k0, k0, 0xffc
-       addu    k1, k1, k0
-       lw      k0, (k1)
-       nop
-       mtc0    k0, CP0_ENTRYLO0
-       mfc0    k1, CP0_EPC
-       tlbwr
-       jr      k1
-       rfe
-       END(except_vec0_r2300)
-
-       __FINIT
-
        /* ABUSE of CPP macros 101. */
 
        /* After this macro runs, the pte faulted on is
index 4974271..ab50b77 100644 (file)
                           _PAGE_VALID | _PAGE_DIRTY); \
        PTE_S   pte, (ptr);
 
-       __INIT
-
-#ifdef CONFIG_64BIT_PHYS_ADDR
-#define GET_PTE_OFF(reg)
-#elif CONFIG_CPU_VR41XX
-#define GET_PTE_OFF(reg)       srl     reg, reg, 3
-#else
-#define GET_PTE_OFF(reg)       srl     reg, reg, 1
-#endif
-
-/*
- * These handlers much be written in a relocatable manner
- * because based upon the cpu type an arbitrary one of the
- * following pieces of code will be copied to the KSEG0
- * vector location.
- */
-       /* TLB refill, EXL == 0, R4xx0, non-R4600 version */
-       .set    noreorder
-       .set    noat
-       LEAF(except_vec0_r4000)
-       .set    mips3
-       GET_PGD(k0, k1)                         # get pgd pointer
-       mfc0    k0, CP0_BADVADDR                # Get faulting address
-       srl     k0, k0, _PGDIR_SHIFT            # get pgd only bits
-
-       sll     k0, k0, 2
-       addu    k1, k1, k0                      # add in pgd offset
-       mfc0    k0, CP0_CONTEXT                 # get context reg
-       lw      k1, (k1)
-       GET_PTE_OFF(k0)                         # get pte offset
-       and     k0, k0, PTEP_INDX_MSK
-       addu    k1, k1, k0                      # add in offset
-       PTE_L   k0, 0(k1)                       # get even pte
-       PTE_L   k1, PTE_SIZE(k1)                # get odd pte
-       PTE_SRL k0, k0, 6                       # convert to entrylo0
-       P_MTC0  k0, CP0_ENTRYLO0                # load it
-       PTE_SRL k1, k1, 6                       # convert to entrylo1
-       P_MTC0  k1, CP0_ENTRYLO1                # load it
-       mtc0_tlbw_hazard
-       tlbwr                                   # write random tlb entry
-       tlbw_eret_hazard
-       eret                                    # return from trap
-       END(except_vec0_r4000)
-
-       /* TLB refill, EXL == 0, R4600 version */
-       LEAF(except_vec0_r4600)
-       .set    mips3
-       GET_PGD(k0, k1)                         # get pgd pointer
-       mfc0    k0, CP0_BADVADDR
-       srl     k0, k0, _PGDIR_SHIFT
-       sll     k0, k0, 2                       # log2(sizeof(pgd_t)
-       addu    k1, k1, k0
-       mfc0    k0, CP0_CONTEXT
-       lw      k1, (k1)
-       GET_PTE_OFF(k0)                         # get pte offset
-       and     k0, k0, PTEP_INDX_MSK
-       addu    k1, k1, k0
-       PTE_L   k0, 0(k1)
-       PTE_L   k1, PTE_SIZE(k1)
-       PTE_SRL k0, k0, 6
-       P_MTC0  k0, CP0_ENTRYLO0
-       PTE_SRL k1, k1, 6
-       P_MTC0  k1, CP0_ENTRYLO1
-       nop
-       tlbwr
-       nop
-       eret
-       END(except_vec0_r4600)
-
-       /* TLB refill, EXL == 0, R52x0 "Nevada" version */
-        /*
-         * This version has a 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
-         * it's consumer are in a different cacheline or a load instruction,
-         * probably any memory reference, is between them.  This is
-         * potencially slower than the R4000 version, so we use this
-         * special version.
-         */
-       .set    noreorder
-       .set    noat
-       LEAF(except_vec0_nevada)
-       .set    mips3
-       mfc0    k0, CP0_BADVADDR                # Get faulting address
-       srl     k0, k0, _PGDIR_SHIFT            # get pgd only bits
-       lw      k1, pgd_current                 # get pgd pointer
-       sll     k0, k0, 2                       # log2(sizeof(pgd_t)
-       addu    k1, k1, k0                      # add in pgd offset
-       lw      k1, (k1)
-       mfc0    k0, CP0_CONTEXT                 # get context reg
-       GET_PTE_OFF(k0)                         # get pte offset
-       and     k0, k0, PTEP_INDX_MSK
-       addu    k1, k1, k0                      # add in offset
-       PTE_L   k0, 0(k1)                       # get even pte
-       PTE_L   k1, PTE_SIZE(k1)                # get odd pte
-       PTE_SRL k0, k0, 6                       # convert to entrylo0
-       P_MTC0  k0, CP0_ENTRYLO0                # load it
-       PTE_SRL k1, k1, 6                       # convert to entrylo1
-       P_MTC0  k1, CP0_ENTRYLO1                # load it
-       nop                                     # QED specified nops
-       nop
-       tlbwr                                   # write random tlb entry
-       nop                                     # traditional nop
-       eret                                    # return from trap
-       END(except_vec0_nevada)
-
-       /* TLB refill, EXL == 0, SB1 with M3 errata handling version */
-       LEAF(except_vec0_sb1)
-#if BCM1250_M3_WAR
-       mfc0    k0, CP0_BADVADDR
-       mfc0    k1, CP0_ENTRYHI
-       xor     k0, k1
-       srl     k0, k0, PAGE_SHIFT+1
-       bnez    k0, 1f
-#endif
-       GET_PGD(k0, k1)                         # get pgd pointer
-       mfc0    k0, CP0_BADVADDR                # Get faulting address
-       srl     k0, k0, _PGDIR_SHIFT            # get pgd only bits
-       sll     k0, k0, 2
-       addu    k1, k1, k0                      # add in pgd offset
-       mfc0    k0, CP0_CONTEXT                 # get context reg
-       lw      k1, (k1)
-       GET_PTE_OFF(k0)                         # get pte offset
-       and     k0, k0, PTEP_INDX_MSK
-       addu    k1, k1, k0                      # add in offset
-       PTE_L   k0, 0(k1)                       # get even pte
-       PTE_L   k1, PTE_SIZE(k1)                # get odd pte
-       PTE_SRL k0, k0, 6                       # convert to entrylo0
-       P_MTC0  k0, CP0_ENTRYLO0                # load it
-       PTE_SRL k1, k1, 6                       # convert to entrylo1
-       P_MTC0  k1, CP0_ENTRYLO1                # load it
-       tlbwr                                   # write random tlb entry
-1:     eret                                    # return from trap
-       END(except_vec0_sb1)
-
-       /* TLB refill, EXL == 0, R4[40]00/R5000 badvaddr hwbug version */
-       LEAF(except_vec0_r45k_bvahwbug)
-       .set    mips3
-       GET_PGD(k0, k1)                         # get pgd pointer
-       mfc0    k0, CP0_BADVADDR
-       srl     k0, k0, _PGDIR_SHIFT
-       sll     k0, k0, 2                       # log2(sizeof(pgd_t)
-       addu    k1, k1, k0
-       mfc0    k0, CP0_CONTEXT
-       lw      k1, (k1)
-#ifndef CONFIG_64BIT_PHYS_ADDR
-       srl     k0, k0, 1
-#endif
-       and     k0, k0, PTEP_INDX_MSK
-       addu    k1, k1, k0
-       PTE_L   k0, 0(k1)
-       PTE_L   k1, PTE_SIZE(k1)
-       nop                             /* XXX */
-       tlbp
-       PTE_SRL k0, k0, 6
-       P_MTC0  k0, CP0_ENTRYLO0
-       PTE_SRL k1, k1, 6
-       mfc0    k0, CP0_INDEX
-       P_MTC0  k1, CP0_ENTRYLO1
-       bltzl   k0, 1f
-       tlbwr
-1:
-       nop
-       eret
-       END(except_vec0_r45k_bvahwbug)
-
-#ifdef CONFIG_SMP
-       /* TLB refill, EXL == 0, R4000 MP badvaddr hwbug version */
-       LEAF(except_vec0_r4k_mphwbug)
-       .set    mips3
-       GET_PGD(k0, k1)                         # get pgd pointer
-       mfc0    k0, CP0_BADVADDR
-       srl     k0, k0, _PGDIR_SHIFT
-       sll     k0, k0, 2                       # log2(sizeof(pgd_t)
-       addu    k1, k1, k0
-       mfc0    k0, CP0_CONTEXT
-       lw      k1, (k1)
-#ifndef CONFIG_64BIT_PHYS_ADDR
-       srl     k0, k0, 1
-#endif
-       and     k0, k0, PTEP_INDX_MSK
-       addu    k1, k1, k0
-       PTE_L   k0, 0(k1)
-       PTE_L   k1, PTE_SIZE(k1)
-       nop                             /* XXX */
-       tlbp
-       PTE_SRL k0, k0, 6
-       P_MTC0  k0, CP0_ENTRYLO0
-       PTE_SRL k1, k1, 6
-       mfc0    k0, CP0_INDEX
-       P_MTC0  k1, CP0_ENTRYLO1
-       bltzl   k0, 1f
-       tlbwr
-1:
-       nop
-       eret
-       END(except_vec0_r4k_mphwbug)
-#endif
-
-       /* TLB refill, EXL == 0, R4000 UP 250MHZ entrylo[01] hwbug version */
-       LEAF(except_vec0_r4k_250MHZhwbug)
-       .set    mips3
-       GET_PGD(k0, k1)                         # get pgd pointer
-       mfc0    k0, CP0_BADVADDR
-       srl     k0, k0, _PGDIR_SHIFT
-       sll     k0, k0, 2                       # log2(sizeof(pgd_t)
-       addu    k1, k1, k0
-       mfc0    k0, CP0_CONTEXT
-       lw      k1, (k1)
-#ifndef CONFIG_64BIT_PHYS_ADDR
-       srl     k0, k0, 1
-#endif
-       and     k0, k0, PTEP_INDX_MSK
-       addu    k1, k1, k0
-       PTE_L   k0, 0(k1)
-       PTE_L   k1, PTE_SIZE(k1)
-       PTE_SRL k0, k0, 6
-       P_MTC0  zero, CP0_ENTRYLO0
-       P_MTC0  k0, CP0_ENTRYLO0
-       PTE_SRL k1, k1, 6
-       P_MTC0  zero, CP0_ENTRYLO1
-       P_MTC0  k1, CP0_ENTRYLO1
-       b       1f
-       tlbwr
-1:
-       nop
-       eret
-       END(except_vec0_r4k_250MHZhwbug)
-
-#ifdef CONFIG_SMP
-       /* TLB refill, EXL == 0, R4000 MP 250MHZ entrylo[01]+badvaddr bug version */
-       LEAF(except_vec0_r4k_MP250MHZhwbug)
-       .set    mips3
-       GET_PGD(k0, k1)                         # get pgd pointer
-       mfc0    k0, CP0_BADVADDR
-       srl     k0, k0, _PGDIR_SHIFT
-       sll     k0, k0, 2                       # log2(sizeof(pgd_t)
-       addu    k1, k1, k0
-       mfc0    k0, CP0_CONTEXT
-       lw      k1, (k1)
-#ifndef CONFIG_64BIT_PHYS_ADDR
-       srl     k0, k0, 1
-#endif
-       and     k0, k0, PTEP_INDX_MSK
-       addu    k1, k1, k0
-       PTE_L   k0, 0(k1)
-       PTE_L   k1, PTE_SIZE(k1)
-       nop                             /* XXX */
-       tlbp
-       PTE_SRL k0, k0, 6
-       P_MTC0  zero, CP0_ENTRYLO0
-       P_MTC0  k0, CP0_ENTRYLO0
-       mfc0    k0, CP0_INDEX
-       PTE_SRL k1, k1, 6
-       P_MTC0  zero, CP0_ENTRYLO1
-       P_MTC0  k1, CP0_ENTRYLO1
-       bltzl   k0, 1f
-       tlbwr
-1:
-       nop
-       eret
-       END(except_vec0_r4k_MP250MHZhwbug)
-#endif
-
-       __FINIT
 
        .set    noreorder
 
@@ -460,6 +195,7 @@ invalid_tlbl:
        PTE_RELOAD(k1, k0)
        mtc0_tlbw_hazard
        tlbwi
+       nop
        tlbw_eret_hazard
        .set    mips3
        eret
@@ -484,6 +220,7 @@ nopage_tlbl:
        PTE_RELOAD(k1, k0)
        mtc0_tlbw_hazard
        tlbwi
+       nop
        tlbw_eret_hazard
        .set    mips3
        eret
@@ -513,6 +250,7 @@ nopage_tlbs:
        PTE_RELOAD(k1, k0)
        mtc0_tlbw_hazard
        tlbwi
+       nop
        tlbw_eret_hazard
        .set    mips3
        eret
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);
index 3ef3584..8720bcc 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/config.h>
 
-#if defined(CONFIG_KGDB)
+#ifdef CONFIG_KGDB
 
 #include <asm/serial.h> /* For the serial port location and base baud */
 
index 3ef3584..8720bcc 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/config.h>
 
-#if defined(CONFIG_KGDB)
+#ifdef CONFIG_KGDB
 
 #include <asm/serial.h> /* For the serial port location and base baud */
 
index 7d838c1..e70ec0e 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -52,7 +52,7 @@
 extern asmlinkage void ocelot_handle_int(void);
 extern void gt64240_irq_init(void);
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        /*
         * Clear all of the interrupts while we change the able around a bit.
@@ -63,15 +63,8 @@ void __init init_IRQ(void)
 
        /* Sets the first-level interrupt dispatcher. */
        set_except_vector(0, ocelot_handle_int);
-       init_generic_irq();
        mips_cpu_irq_init(0);
        rm7k_cpu_irq_init(8);
 
        gt64240_irq_init();
-
-#ifdef CONFIG_KGDB
-       printk("start kgdb ...\n");
-       set_debug_traps();
-       breakpoint();   /* you may move this line to whereever you want :-) */
-#endif
 }
index ae1930e..ebd7a43 100644 (file)
@@ -40,11 +40,13 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        return irq_tab[slot][pin];
 }
 
-void __init pcibios_fixup_irqs(void)
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
 {
+       return 0;
 }
 
-#if CONFIG_KGDB
+#ifdef CONFIG_KGDB
 /*
  * The PCI scan may have moved the saa9730 I/O address, so reread
  * the address here.
@@ -61,6 +63,6 @@ static void atlas_saa9730_base_fixup (struct pci_dev *pdev)
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730,
-       atlas_saa9730_base_fixup);
+        atlas_saa9730_base_fixup);
 
 #endif
index 84c7e98..57e1ca2 100644 (file)
@@ -77,7 +77,7 @@ static void qube_raq_galileo_fixup(struct pci_dev *dev)
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_GALILEO, PCI_ANY_ID,
-       qube_raq_galileo_fixup);
+        qube_raq_galileo_fixup);
 
 static char irq_tab_cobalt[] __initdata = {
   [COBALT_PCICONF_CPU]     = 0,
@@ -104,3 +104,9 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 
        return irq_tab_cobalt[slot];
 }
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
index 785bc03..b345e52 100644 (file)
@@ -18,4 +18,4 @@ static void ddb5074_fixup(struct pci_dev *dev)
 }
 
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
-       ddb5074_fixup);
+         ddb5074_fixup);
index 25bf493..6abdc88 100644 (file)
@@ -75,4 +75,4 @@ static void ddb5477_amd_lance_fixup(struct pci_dev *dev)
 }
 
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
-          ddb5477_amd_lance_fixup);
+         ddb5477_amd_lance_fixup);
index 413bb5b..e2bc977 100644 (file)
@@ -40,3 +40,9 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
        return irq_tab_ev96100[slot][pin];
 }
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
index f64529b..3e66b0a 100644 (file)
@@ -1,7 +1,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <asm/pci_channel.h>
 #include <asm/ip32/ip32_ints.h>
 /*
  * O2 has up to 5 PCI devices connected into the MACE bridge.  The device
@@ -44,3 +43,9 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
        return irq_tab_mace[slot][pin];
 }
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
index 7b032ef..2290ea4 100644 (file)
@@ -72,3 +72,9 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 
        return irq_tab_ite8172g[slot][pin];
 }
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
index a796ef1..0c7c164 100644 (file)
@@ -67,3 +67,9 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 
        return irq_tab_ivr[slot][pin];
 }
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
index 682edfa..f869608 100644 (file)
@@ -88,6 +88,12 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        return irq;
 }
 
+/* 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)
 {
        /* SMSC SLC90E66 IDE uses irq 14, 15 (default) */
index bcde09e..b9296d9 100644 (file)
@@ -43,11 +43,12 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        return pci_irq[virq];
 }
 
-void __init pcibios_fixup_irqs(void)
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
 {
+       return 0;
 }
 
-
 static void __init malta_piix_func0_fixup(struct pci_dev *pdev)
 {
        unsigned char reg_val;
@@ -99,4 +100,4 @@ static void __init malta_piix_func1_fixup(struct pci_dev *pdev)
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
-       malta_piix_func1_fixup);
+        malta_piix_func1_fixup);
index 8e5db12..09d6b36 100644 (file)
@@ -42,3 +42,9 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 
        return irq_tab_mpc30x[slot];
 }
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
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");
+}
index 2182719..de4e443 100644 (file)
@@ -9,6 +9,9 @@
  *
  * Copyright (C) 2000-2001 Toshiba Corporation 
  *
+ * 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
@@ -116,108 +119,22 @@ int pci_get_irq(struct pci_dev *dev, int pin)
        return irq;
 }
 
-
-#ifdef  TX4927_SUPPORT_PCI_66
-extern int tx4927_pci66;
-extern void tx4927_pci66_setup(void);
-#endif
-extern void tx4927_pci_setup(void);
-
-#ifdef  TX4927_SUPPORT_PCI_66
-int tx4927_pci66_check(void)
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
-       struct pci_dev *dev;
-       unsigned short stat;
-       int cap66 = 1;
-
-       if (tx4927_pci66 < 0)
-               return 0;
-
-       /* check 66MHz capability */
-       pci_for_each_dev(dev) {
-               if (cap66) {
-                       pci_read_config_word(dev, PCI_STATUS, &stat);
-                       if (!(stat & PCI_STATUS_66MHZ)) {
-                               printk(KERN_INFO
-                                      "PCI: %02x:%02x not 66MHz capable.\n",
-                                      dev->bus->number, dev->devfn);
-                               cap66 = 0;
-                       }
-               }
-       }
-       return cap66;
-}
-#endif
-
-void __init pcibios_fixup_irqs(void)
-{
-       unsigned char pin;
        unsigned char irq;
-       struct pci_dev *dev;
-       unsigned int id;
-
-#ifdef  TX4927_SUPPORT_PCI_66
-       if (tx4927_pci66_check()) {
-               tx4927_pci66_setup();
-               tx4927_pci_setup();     /* Reinitialize PCIC */
-       }
-#endif
 
-       pci_for_each_dev(dev) {
-               DBG("FIXUP:\n");
-               DBG(" devfn=0x%02x (0x%02x:0x%02x)\n",
-                   dev->devfn, PCI_SLOT(dev->devfn),
-                   PCI_FUNC(dev->devfn));
+       printk("PCI Setup for pin %d \n", pin);
 
-               pci_read_config_dword(dev, PCI_VENDOR_ID, &id);
-               DBG(" id=0x%08x\n", id);
+       if (dev->device == 0x9130) /* IDE */
+               irq = 14;
+       else
+               irq = pci_get_irq(dev, pin);
 
-               pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-               DBG(" line=0x%02x/%d\n", irq, irq);
-
-               pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-               DBG(" pin=%d\n", pin);
-
-#ifdef DEBUG
-               {
-                       unsigned int tmp;
-                       pci_read_config_dword(dev, 0x10, &tmp);
-                       DBG(" bar0:0x10=0x%08x\n", tmp);
-                       pci_read_config_dword(dev, 0x14, &tmp);
-                       DBG(" bar1:0x14=0x%08x\n", tmp);
-                       pci_read_config_dword(dev, 0x1c, &tmp);
-                       DBG(" bar2:0x1c=0x%08x\n", tmp);
-                       pci_read_config_dword(dev, 0x20, &tmp);
-                       DBG(" bar3:0x20=0x%08x\n", tmp);
-                       pci_read_config_dword(dev, 0x24, &tmp);
-                       DBG(" bar4:0x24=0x%08x\n", tmp);
-               }
-#endif
-
-               irq = 0;
-
-               if (id == 0x91301055) { /* ide */
-                       irq = 14;
-               }
-
-               if (pin == 0) {
-                       DBG(" auto irq (now=%d) -- skipping pin=0\n", irq);
-               } else if (irq) {
-                       DBG(" auto irq (now=%d) -- skipping hardcoded irq\n", irq);
-               } else {
-                       DBG(" auto irq (was=%d)\n", irq);
-                       irq = pci_get_irq(dev, pin);
-                       pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
-                                             irq);
-                       dev->irq = irq;
-                       DBG(" auto irq (now=%d)\n", irq);
-               }
-
-               pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-               printk(KERN_INFO
-                      "PCI: 0x%02x:0x%02x(0x%02x,0x%02x) IRQ=%d\n",
-                      dev->bus->number, dev->devfn, PCI_SLOT(dev->devfn),
-                      PCI_FUNC(dev->devfn), irq);
+       return irq;
+}
 
-       }
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
 }
index 563fb2c..c8ef01a 100644 (file)
@@ -5,14 +5,13 @@
  *
  * SNI specific PCI support for RM200/RM300.
  *
- * Copyright (C) 1997 - 2000, 2003 Ralf Baechle
+ * Copyright (C) 1997 - 2000, 2003, 04 Ralf Baechle (ralf@linux-mips.org)
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 
 #include <asm/mipsregs.h>
-#include <asm/pci_channel.h>
 #include <asm/sni.h>
 
 /*
@@ -82,3 +81,9 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 
        return irq_tab_rm200[slot][pin];
 }
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
index 2f40a8c..b7a8b9a 100644 (file)
@@ -7,6 +7,8 @@
  * Author: MontaVista Software, Inc.
  *             ppopov@mvista.com or source@mvista.com
  *
+ * Copyright (C) 2004 by 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
@@ -32,7 +34,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 
-#include <asm/pci_channel.h>
 #include <asm/it8172/it8172.h>
 #include <asm/it8172/it8172_pci.h>
 
index 136c449..0e0daad 100644 (file)
@@ -4,6 +4,7 @@
  *              ahennessy@mvista.com
  *
  * Copyright (C) 2000-2001 Toshiba Corporation
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
  *
  * Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c
  *
@@ -38,7 +39,6 @@
 #include <linux/init.h>
 
 #include <asm/addrspace.h>
-#include <asm/pci_channel.h>
 #include <asm/jmr3927/jmr3927.h>
 #include <asm/debug.h>
 
index 9044ff9..43863ab 100644 (file)
@@ -4,6 +4,7 @@
  *              ahennessy@mvista.com       
  *
  * Copyright (C) 2000-2001 Toshiba Corporation 
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
  *
  * Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c
  *
@@ -12,6 +13,9 @@
  * Much of the code is derived from the original DDB5074 port by 
  * Geert Uytterhoeven <geert@sonycom.com>
  *
+ * Copyright 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
 #include <linux/init.h>
 
 #include <asm/addrspace.h>
-#include <asm/pci_channel.h>
 #include <asm/tx4927/tx4927_pci.h>
 #include <asm/debug.h>
 
 /* initialize in setup */
 struct resource pci_io_resource = {
-       "pci IO space",
-       (PCIBIOS_MIN_IO),
-       ((PCIBIOS_MIN_IO) + (TX4927_PCIIO_SIZE)) - 1,
-       IORESOURCE_IO
+       .name   = "TX4927 PCI IO SPACE",
+       .start  = 0x1000,
+       .end    = (0x1000 + (TX4927_PCIIO_SIZE)) - 1,
+       .flags  = IORESOURCE_IO
 };
 
 /* initialize in setup */
 struct resource pci_mem_resource = {
-       "pci memory space",
-       TX4927_PCIMEM,
-       TX4927_PCIMEM + TX4927_PCIMEM_SIZE - 1,
-       IORESOURCE_MEM
-};
-
-extern struct pci_ops tx4927_pci_ops;
-
-/*
- * h/w only supports devices 0x00 to 0x14
- */
-struct pci_controller tx4927_controller = {
-       .pci_ops        = &tx4927_pci_ops,
-       .io_resource    = &pci_io_resource,
-       .mem_resource   = &pci_mem_resource,
+       .name   = "TX4927 PCI MEM SPACE",
+       .start  = TX4927_PCIMEM,
+       .end    = TX4927_PCIMEM + TX4927_PCIMEM_SIZE - 1,
+       .flags  = IORESOURCE_MEM
 };
 
-static int mkaddr(unsigned char bus, unsigned char dev_fn,
-       unsigned char where, int *flagsp)
+static int mkaddr(int bus, int dev_fn, int where, int *flagsp)
 {
        if (bus > 0) {
                /* Type 1 configuration */
@@ -107,107 +98,49 @@ static int check_abort(int flags)
        return code;
 }
 
-/*
- * We can't address 8 and 16 bit words directly.  Instead we have to
- * read/write a 32bit word and mask/modify the data we actually want.
- */
-static int tx4927_pcibios_read_config_byte(struct pci_dev *dev,
-                                          int where, unsigned char *val)
+static int tx4927_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+               int size, u32 * val)
 {
-       int flags, retval;
-       unsigned char bus, func_num;
+       int flags, retval, dev, busno, func;
 
-       db_assert((where & 3) == 0);
-       db_assert(where < (1 << 8));
+       busno = bus->number;
+        dev = PCI_SLOT(devfn);
+        func = PCI_FUNC(devfn);
 
-       /* check if the bus is top-level */
-       if (dev->bus->parent != NULL) {
-               bus = dev->bus->number;
-               db_assert(bus != 0);
-       } else {
-               bus = 0;
+       if (size == 2) {
+               if (where & 1)
+                       return PCIBIOS_BAD_REGISTER_NUMBER;
        }
 
-       func_num = PCI_FUNC(dev->devfn);
-       if (mkaddr(bus, dev->devfn, where, &flags))
-               return -1;
-#ifdef __BIG_ENDIAN
-       *val =
-           *(volatile u8 *) ((ulong) & tx4927_pcicptr->
-                             g2pcfgdata | ((where & 3) ^ 3));
-#else
-       *val =
-           *(volatile u8 *) ((ulong) & tx4927_pcicptr->
-                             g2pcfgdata | (where & 3));
-#endif
-       retval = check_abort(flags);
-       if (retval == PCIBIOS_DEVICE_NOT_FOUND)
-               *val = 0xff;
-       return retval;
-}
-
-static int tx4927_pcibios_read_config_word(struct pci_dev *dev,
-                                          int where, unsigned short *val)
-{
-       int flags, retval;
-       unsigned char bus, func_num;
-
-       if (where & 1)
-               return PCIBIOS_BAD_REGISTER_NUMBER;
-
-       db_assert((where & 3) == 0);
-       db_assert(where < (1 << 8));
+       if (size == 4) {
+               if (where & 3)
+                       return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
 
        /* check if the bus is top-level */
-       if (dev->bus->parent != NULL) {
-               bus = dev->bus->number;
-               db_assert(bus != 0);
+       if (bus->parent != NULL) {
+               busno = bus->number;
        } else {
-               bus = 0;
+               busno = 0;
        }
 
-       func_num = PCI_FUNC(dev->devfn);
-       if (mkaddr(bus, dev->devfn, where, &flags))
+       if (mkaddr(busno, devfn, where, &flags))
                return -1;
-#ifdef __BIG_ENDIAN
-       *val =
-           *(volatile u16 *) ((ulong) & tx4927_pcicptr->
-                              g2pcfgdata | ((where & 3) ^ 2));
-#else
-       *val =
-           *(volatile u16 *) ((ulong) & tx4927_pcicptr->
-                              g2pcfgdata | (where & 3));
-#endif
-       retval = check_abort(flags);
-       if (retval == PCIBIOS_DEVICE_NOT_FOUND)
-               *val = 0xffff;
-       return retval;
-}
-
-static int tx4927_pcibios_read_config_dword(struct pci_dev *dev,
-                                           int where, unsigned int *val)
-{
-       int flags, retval;
-       unsigned char bus, func_num;
-
-       if (where & 3)
-               return PCIBIOS_BAD_REGISTER_NUMBER;
 
-       db_assert((where & 3) == 0);
-       db_assert(where < (1 << 8));
-
-       /* check if the bus is top-level */
-       if (dev->bus->parent != NULL) {
-               bus = dev->bus->number;
-               db_assert(bus != 0);
-       } else {
-               bus = 0;
+       switch (size) {
+       case 1:
+               *val = *(volatile u8 *) ((ulong) & tx4927_pcicptr->
+                              g2pcfgdata | (where & 3));
+               break;
+       case 2:
+               *val = *(volatile u16 *) ((ulong) & tx4927_pcicptr->
+                               g2pcfgdata | (where & 3));
+               break;
+       case 4:
+               *val = tx4927_pcicptr->g2pcfgdata;
+               break;
        }
 
-       func_num = PCI_FUNC(dev->devfn);
-       if (mkaddr(bus, dev->devfn, where, &flags))
-               return -1;
-       *val = tx4927_pcicptr->g2pcfgdata;
        retval = check_abort(flags);
        if (retval == PCIBIOS_DEVICE_NOT_FOUND)
                *val = 0xffffffff;
@@ -215,92 +148,62 @@ static int tx4927_pcibios_read_config_dword(struct pci_dev *dev,
        return retval;
 }
 
-static int tx4927_pcibios_write_config_byte(struct pci_dev *dev,
-                                           int where, unsigned char val)
+static int tx4927_pcibios_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+                               int size, u32 val)
 {
-       int flags;
-       unsigned char bus, func_num;
-
-       /* check if the bus is top-level */
-       if (dev->bus->parent != NULL) {
-               bus = dev->bus->number;
-               db_assert(bus != 0);
-       } else {
-               bus = 0;
+       int flags, dev, busno, func;
+       busno = bus->number;
+        dev = PCI_SLOT(devfn);
+        func = PCI_FUNC(devfn);
+
+       if (size == 1) {
+               if (where & 1)
+                       return PCIBIOS_BAD_REGISTER_NUMBER;
        }
 
-       func_num = PCI_FUNC(dev->devfn);
-       if (mkaddr(bus, dev->devfn, where, &flags))
-               return -1;
-#ifdef __BIG_ENDIAN
-       *(volatile u8 *) ((ulong) & tx4927_pcicptr->
-                         g2pcfgdata | ((where & 3) ^ 3)) = val;
-#else
-       *(volatile u8 *) ((ulong) & tx4927_pcicptr->
-                         g2pcfgdata | (where & 3)) = val;
-#endif
-       return check_abort(flags);
-}
-
-static int tx4927_pcibios_write_config_word(struct pci_dev *dev,
-                                           int where, unsigned short val)
-{
-       int flags;
-       unsigned char bus, func_num;
-
-       if (where & 1)
-               return PCIBIOS_BAD_REGISTER_NUMBER;
+       if (size == 4) {
+               if (where & 3)
+                       return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
 
        /* check if the bus is top-level */
-       if (dev->bus->parent != NULL) {
-               bus = dev->bus->number;
-               db_assert(bus != 0);
+       if (bus->parent != NULL) {
+               busno = bus->number;
        } else {
-               bus = 0;
+               busno = 0;
        }
 
-       func_num = PCI_FUNC(dev->devfn);
-       if (mkaddr(bus, dev->devfn, where, &flags))
+       if (mkaddr(busno, devfn, where, &flags))
                return -1;
-#ifdef __BIG_ENDIAN
-       *(volatile u16 *) ((ulong) & tx4927_pcicptr->
-                          g2pcfgdata | ((where & 3) ^ 2)) = val;
-#else
-       *(volatile u16 *) ((ulong) & tx4927_pcicptr->
-                          g2pcfgdata | (where & 3)) = val;
-#endif
-       return check_abort(flags);
-}
-
-static int tx4927_pcibios_write_config_dword(struct pci_dev *dev,
-                                            int where, unsigned int val)
-{
-       int flags;
-       unsigned char bus, func_num;
 
-       if (where & 3)
-               return PCIBIOS_BAD_REGISTER_NUMBER;
-
-       /* check if the bus is top-level */
-       if (dev->bus->parent != NULL) {
-               bus = dev->bus->number;
-               db_assert(bus != 0);
-       } else {
-               bus = 0;
+       switch (size) {
+       case 1:
+                *(volatile u8 *) ((ulong) & tx4927_pcicptr->
+                          g2pcfgdata | (where & 3)) = val;
+               break;
+
+       case 2:
+               *(volatile u16 *) ((ulong) & tx4927_pcicptr->
+                           g2pcfgdata | (where & 3)) = val;
+               break;
+       case 4:
+               tx4927_pcicptr->g2pcfgdata = val;
+               break;
        }
 
-       func_num = PCI_FUNC(dev->devfn);
-       if (mkaddr(bus, dev->devfn, where, &flags))
-               return -1;
-       tx4927_pcicptr->g2pcfgdata = val;
        return check_abort(flags);
 }
 
 struct pci_ops tx4927_pci_ops = {
-       tx4927_pcibios_read_config_byte,
-       tx4927_pcibios_read_config_word,
-       tx4927_pcibios_read_config_dword,
-       tx4927_pcibios_write_config_byte,
-       tx4927_pcibios_write_config_word,
-       tx4927_pcibios_write_config_dword
+       tx4927_pcibios_read_config,
+       tx4927_pcibios_write_config
+};
+
+/*
+ * h/w only supports devices 0x00 to 0x14
+ */
+struct pci_controller tx4927_controller = {
+       .pci_ops        = &tx4927_pci_ops,
+       .io_resource    = &pci_io_resource,
+       .mem_resource   = &pci_mem_resource,
 };
index 5bc21b2..73f9cee 100644 (file)
@@ -3,7 +3,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 
-#include <asm/pci_channel.h>
 #include <asm/debug.h>
 
 #include <asm/ddb5xxx/ddb5xxx.h>
@@ -54,6 +53,12 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        return irq_map[slot];
 }
 
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
 void __init ddb_pci_reset_bus(void)
 {
        u32 temp;
index 945e59b..90dd495 100644 (file)
@@ -3,7 +3,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 
-#include <asm/pci_channel.h>
 #include <asm/debug.h>
 
 #include <asm/ddb5xxx/ddb5xxx.h>
@@ -68,6 +67,12 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        return irq_map[slot];
 }
 
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
 void __init ddb_pci_reset_bus(void)
 {
        u32 temp;
index fd94115..4ddd53e 100644 (file)
@@ -4,6 +4,8 @@
  * Copyright (C) 2001 MontaVista Software Inc.
  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
  *
+ * Copyright (C) 2004 by 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
@@ -15,7 +17,6 @@
 #include <linux/pci.h>
 
 #include <asm/bootinfo.h>
-#include <asm/pci_channel.h>
 #include <asm/debug.h>
 
 #include <asm/ddb5xxx/ddb5xxx.h>
@@ -175,6 +176,12 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        return irq;
 }
 
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
 void ddb_pci_reset_bus(void)
 {
        u32 temp;
index 8f2becb..f9457ea 100644 (file)
@@ -6,6 +6,8 @@
  * Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
  *
+ * Copyright (C) 2004 by 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
@@ -31,8 +33,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 
-#include <asm/pci_channel.h>
-
 static struct resource pci_io_resource = {
        .name   = "io pci IO space",
        .start  = 0x10000000,
index b996766..068e0e5 100644 (file)
@@ -4,7 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2003 Christoph Hellwig (hch@lst.de)
- * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <asm/sn/arch.h>
 #include <asm/pci/bridge.h>
-#include <asm/pci_channel.h>
 #include <asm/paccess.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/sn0/hub.h>
 
+extern unsigned int allocate_irqno(void);
+
 /*
  * Max #PCI busses we can handle; ie, max #PCI bridges.
  */
@@ -81,7 +82,7 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
        else
                res = get_dbe(*value, (u32 *) addr);
 
-       return PCIBIOS_SUCCESSFUL;
+       return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
 
 oh_my_gawd:
 
@@ -110,6 +111,79 @@ oh_my_gawd:
        return PCIBIOS_SUCCESSFUL;
 }
 
+static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
+                                int where, int size, u32 * value)
+{
+       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+       bridge_t *bridge = bc->base;
+       int busno = bus->number;
+       int slot = PCI_SLOT(devfn);
+       int fn = PCI_FUNC(devfn);
+       volatile void *addr;
+       u32 cf, shift, mask;
+       int res;
+
+       bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
+       if (get_dbe(cf, (u32 *) addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * IOC3 is fucked fucked beyond believe ...  Don't even give the
+        * generic PCI code a chance to look at it for real ...
+        */
+       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+               goto oh_my_gawd;
+
+       bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
+
+       if (size == 1)
+               res = get_dbe(*value, (u8 *) addr);
+       else if (size == 2)
+               res = get_dbe(*value, (u16 *) addr);
+       else
+               res = get_dbe(*value, (u32 *) addr);
+
+       return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+
+oh_my_gawd:
+
+       /*
+        * IOC3 is fucked fucked beyond believe ...  Don't even give the
+        * generic PCI code a chance to look at the wrong register.
+        */
+       if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
+               *value = 0;
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       /*
+        * IOC3 is fucked fucked beyond believe ...  Don't try to access
+        * anything but 32-bit words ...
+        */
+       bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | where];
+
+       if (get_dbe(cf, (u32 *) addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       shift = ((where & 3) << 3);
+       mask = (0xffffffffU >> ((4 - size) << 3));
+       *value = (cf >> shift) & mask;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_read_config(struct pci_bus *bus, unsigned int devfn,
+                          int where, int size, u32 * value)
+{
+       if (bus->number > 0)
+               return pci_conf1_read_config(bus, devfn, where, size, value);
+
+       return pci_conf0_read_config(bus, devfn, where, size, value);
+}
+
 static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
                                  int where, int size, u32 value)
 {
@@ -176,16 +250,95 @@ oh_my_gawd:
        return PCIBIOS_SUCCESSFUL;
 }
 
+static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
+                                 int where, int size, u32 value)
+{
+       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+       bridge_t *bridge = bc->base;
+       int slot = PCI_SLOT(devfn);
+       int fn = PCI_FUNC(devfn);
+       int busno = bus->number;
+       volatile void *addr;
+       u32 cf, shift, mask, smask;
+       int res;
+
+       bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
+       if (get_dbe(cf, (u32 *) addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * IOC3 is fucked fucked beyond believe ...  Don't even give the
+        * generic PCI code a chance to look at it for real ...
+        */
+       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+               goto oh_my_gawd;
+
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
+
+       if (size == 1) {
+               res = put_dbe(value, (u8 *) addr);
+       } else if (size == 2) {
+               res = put_dbe(value, (u16 *) addr);
+       } else {
+               res = put_dbe(value, (u32 *) addr);
+       }
+
+       if (res)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+
+oh_my_gawd:
+
+       /*
+        * IOC3 is fucked fucked beyond believe ...  Don't even give the
+        * generic PCI code a chance to touch the wrong register.
+        */
+       if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
+               return PCIBIOS_SUCCESSFUL;
+
+       /*
+        * IOC3 is fucked fucked beyond believe ...  Don't try to access
+        * anything but 32-bit words ...
+        */
+       addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+
+       if (get_dbe(cf, (u32 *) addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       shift = ((where & 3) << 3);
+       mask = (0xffffffffU >> ((4 - size) << 3));
+       smask = mask << shift;
+
+       cf = (cf & ~smask) | ((value & mask) << shift);
+       if (put_dbe(cf, (u32 *) addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_write_config(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 value)
+{
+       if (bus->number > 0)
+               return pci_conf1_write_config(bus, devfn, where, size, value);
+
+       return pci_conf0_write_config(bus, devfn, where, size, value);
+}
+
 static struct pci_ops bridge_pci_ops = {
-       .read = pci_conf0_read_config,
-       .write = pci_conf0_write_config,
+       .read = pci_read_config,
+       .write = pci_write_config,
 };
 
 int __init bridge_probe(nasid_t nasid, int widget_id, int masterwid)
 {
+       unsigned long offset = NODE_OFFSET(nasid);
        struct bridge_controller *bc;
-       bridge_t *bridge;
        static int num_bridges = 0;
+       bridge_t *bridge;
+       int slot;
 
        printk("a bridge\n");
 
@@ -193,21 +346,23 @@ int __init bridge_probe(nasid_t nasid, int widget_id, int masterwid)
        if (!num_bridges)
                ioport_resource.end = ~0UL;
 
-       bc = &bridges[num_bridges++];
+       bc = &bridges[num_bridges];
 
        bc->pc.pci_ops          = &bridge_pci_ops;
        bc->pc.mem_resource     = &bc->mem;
        bc->pc.io_resource      = &bc->io;
 
+       bc->pc.index            = num_bridges;
+
        bc->mem.name            = "Bridge PCI MEM";
-       bc->pc.mem_offset       = 0;
+       bc->pc.mem_offset       = offset;
        bc->mem.start           = 0;
        bc->mem.end             = ~0UL;
        bc->mem.flags           = IORESOURCE_MEM;
 
        bc->io.name             = "Bridge IO MEM";
+       bc->pc.io_offset        = offset;
        bc->io.start            = 0UL;
-       bc->pc.io_offset        = 0UL;
        bc->io.end              = ~0UL;
        bc->io.flags            = IORESOURCE_IO;
 
@@ -231,7 +386,7 @@ int __init bridge_probe(nasid_t nasid, int widget_id, int masterwid)
        /*
         * Until otherwise set up, assume all interrupts are from slot 0
         */
-       bridge->b_int_device = (u32) 0x0;
+       bridge->b_int_device = 0x0;
 
        /*
         * swap pio's to pci mem and io space (big windows)
@@ -248,11 +403,18 @@ int __init bridge_probe(nasid_t nasid, int widget_id, int masterwid)
        bridge->b_dir_map = (masterwid << 20);  /* DMA */
        bridge->b_int_enable = 0;
 
+       for (slot = 0; slot < 8; slot ++) {
+               bridge->b_device[slot].reg |= BRIDGE_DEV_SWAP_DIR;
+               bc->pci_int[slot] = -1;
+       }
        bridge->b_wid_tflush;     /* wait until Bridge PIO complete */
 
        bc->base = bridge;
 
        register_pci_controller(&bc->pc);
+
+       num_bridges++;
+
        return 0;
 }
 
@@ -268,17 +430,13 @@ int __init bridge_probe(nasid_t nasid, int widget_id, int masterwid)
 int __devinit pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
-       int irq;
+       int irq = bc->pci_int[slot];
 
-       irq = allocate_irqno();
-
-       /*
-        * Argh...  This API doesn't handle with errors at all ...
-        */
        if (irq == -1) {
-               printk(KERN_ERR "Can't allocate interrupt for PCI device %s\n",
-                      pci_name(dev));
-               return -1;
+               irq = bc->pci_int[slot] = request_bridge_irq(bc);
+               if (irq < 0)
+                       panic("Can't allocate interrupt for PCI device %s\n",
+                             pci_name(dev));
        }
 
        irq_to_bridge[irq] = bc;
@@ -287,6 +445,12 @@ int __devinit pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        return irq;
 }
 
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
 /*
  * Device might live on a subordinate PCI bus.  XXX Walk up the chain of buses
  * to find the slot number in sense of the bridge device register.
@@ -294,7 +458,7 @@ int __devinit pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
  * settings.
  */
 
-static void __init pci_disable_swapping(struct pci_dev *dev)
+static inline void pci_disable_swapping(struct pci_dev *dev)
 {
        struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
        bridge_t *bridge = bc->base;
@@ -305,7 +469,7 @@ static void __init pci_disable_swapping(struct pci_dev *dev)
        bridge->b_widget.w_tflush;      /* Flush */
 }
 
-static void __init pci_enable_swapping(struct pci_dev *dev)
+static inline void pci_enable_swapping(struct pci_dev *dev)
 {
        struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
        bridge_t *bridge = bc->base;
@@ -318,122 +482,8 @@ static void __init pci_enable_swapping(struct pci_dev *dev)
 
 static void __init pci_fixup_ioc3(struct pci_dev *d)
 {
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(d->bus);
-       unsigned long offset = NODE_OFFSET(bc->nasid);
-
-       printk("PCI: Fixing base addresses for IOC3 device %s\n", pci_name(d));
-
-       d->resource[0].start |= offset;
-       d->resource[0].end |= offset;
-
        pci_disable_swapping(d);
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
-        pci_fixup_ioc3);
-
-static void __init pci_fixup_isp1020(struct pci_dev *d)
-{
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(d->bus);
-       unsigned short command;
-
-       d->resource[0].start |= (unsigned long) bc->nasid << 32;
-       printk("PCI: Fixing isp1020 in [bus:slot.fn] %s\n", pci_name(d));
-
-       /*
-        * Configure device to allow bus mastering, i/o and memory mapping.
-        * Older qlogicisp driver expects to have the IO space enable
-        * bit set. Things stop working if we program the controllers as not
-        * having PCI_COMMAND_MEMORY, so we have to fudge the mem_flags.
-        */
-       pci_set_master(d);
-       pci_read_config_word(d, PCI_COMMAND, &command);
-       command |= PCI_COMMAND_MEMORY;
-       command |= PCI_COMMAND_IO;
-       pci_write_config_word(d, PCI_COMMAND, command);
-       d->resource[1].flags |= 1;
-
-       pci_enable_swapping(d);
-}
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020,
-        pci_fixup_isp1020);
-
-static void __init pci_fixup_isp2x00(struct pci_dev *d)
-{
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(d->bus);
-       bridge_t *bridge = bc->base;
-       bridgereg_t devreg;
-       int i;
-       int slot = PCI_SLOT(d->devfn);
-       unsigned int start;
-       unsigned short command;
-
-       printk("PCI: Fixing isp2x00 in [bus:slot.fn] %s\n", pci_name(d));
-
-       /* set the resource struct for this device */
-       start = (u32) (u64) bridge;     /* yes, we want to lose the upper 32 bits here */
-       start |= BRIDGE_DEVIO(slot);
-
-       d->resource[0].start = start;
-       d->resource[0].end = d->resource[0].start + 0xff;
-       d->resource[0].flags = IORESOURCE_IO;
-
-       d->resource[1].start = start;
-       d->resource[1].end = d->resource[0].start + 0xfff;
-       d->resource[1].flags = IORESOURCE_MEM;
-
-       /*
-        * set the bridge device(x) reg for this device
-        */
-       devreg = bridge->b_device[slot].reg;
-       /* point device(x) to it appropriate small window */
-       devreg &= ~BRIDGE_DEV_OFF_MASK;
-       devreg |= (start >> 20) & BRIDGE_DEV_OFF_MASK;
-       bridge->b_device[slot].reg = devreg;
-
-       pci_enable_swapping(d);
-
-       /* set card's base addr reg */
-       //pci_write_config_dword(d, PCI_BASE_ADDRESS_0, 0x500001);
-       //pci_write_config_dword(d, PCI_BASE_ADDRESS_1, 0x8b00000);
-       //pci_write_config_dword(d, PCI_ROM_ADDRESS, 0x8b20000);
-
-       /* I got these from booting irix on system... */
-       pci_write_config_dword(d, PCI_BASE_ADDRESS_0, 0x200001);
-       //pci_write_config_dword(d, PCI_BASE_ADDRESS_1, 0xf800000);
-       pci_write_config_dword(d, PCI_ROM_ADDRESS, 0x10200000);
-
-       pci_write_config_dword(d, PCI_BASE_ADDRESS_1, start);
-       //pci_write_config_dword(d, PCI_ROM_ADDRESS, (start | 0x20000));
-
-       /* set cache line size */
-       pci_write_config_dword(d, PCI_CACHE_LINE_SIZE, 0xf080);
-
-       /* set pci bus timeout */
-       bridge->b_bus_timeout |= BRIDGE_BUS_PCI_RETRY_HLD(0x3);
-       bridge->b_wid_tflush;
-       printk("PCI: bridge bus timeout= 0x%x \n", bridge->b_bus_timeout);
-
-       /* set host error field */
-       bridge->b_int_host_err = 0x44;
-       bridge->b_wid_tflush;
-
-       bridge->b_wid_tflush;   /* wait until Bridge PIO complete */
-       for (i = 0; i < 8; i++)
-               printk("PCI: device(%d)= 0x%x\n", i,
-                      bridge->b_device[i].reg);
-
-       /* configure device to allow bus mastering, i/o and memory mapping */
-       pci_set_master(d);
-       pci_read_config_word(d, PCI_COMMAND, &command);
-       command |= PCI_COMMAND_MEMORY;
-       command |= PCI_COMMAND_IO;
-       pci_write_config_word(d, PCI_COMMAND, command);
-       /*d->resource[1].flags |= 1; */
-}
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100,
-        pci_fixup_isp2x00);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200,
-        pci_fixup_isp2x00);
+       pci_fixup_ioc3);
index 3b3e194..1faeb03 100644 (file)
@@ -4,6 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2000, 2001 Keith M Wesolowski
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -11,7 +12,6 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/types.h>
-#include <asm/pci_channel.h>
 #include <asm/ip32/mace.h>
 #include <asm/ip32/ip32_ints.h>
 
index 24943a2..95a0287 100644 (file)
@@ -4,6 +4,7 @@
  *              ahennessy@mvista.com
  *
  * Copyright (C) 2000-2001 Toshiba Corporation
+ * Copyright (C) 2004 by 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
@@ -30,7 +31,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 
-#include <asm/pci_channel.h>
 #include <asm/jmr3927/jmr3927.h>
 #include <asm/debug.h>
 
index d104360..ae3cc4b 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000, 2001 Keith M Wesolowski
+ * Copyright (C) 2000, 2001, 04 Keith M Wesolowski
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -12,7 +12,6 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <asm/pci_channel.h>
 #include <linux/delay.h>
 #include <asm/bootinfo.h>
 
@@ -66,6 +65,7 @@ early_initcall(lasat_pci_setup);
 #define LASATINT_PCIB   6
 #define LASATINT_PCIC   7
 #define LASATINT_PCID   8
+
 int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
     switch (slot) {
@@ -87,3 +87,9 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 
     return -1;
 }
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
index 8c7c385..b32343e 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2001,2002,2003 Broadcom Corporation
+ * Copyright (C) 2004 by 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
@@ -36,9 +37,9 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/console.h>
+#include <linux/tty.h>
 
 #include <asm/io.h>
-#include <asm/pci_channel.h>
 
 #include <asm/sibyte/sb1250_defs.h>
 #include <asm/sibyte/sb1250_regs.h>
@@ -89,6 +90,12 @@ int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        return dev->irq;
 }
 
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
 /*
  * Some checks before doing config cycles:
  * In PCI Device Mode, hide everything on bus 0 except the LDT host
@@ -181,22 +188,22 @@ struct pci_ops sb1250_pci_ops = {
 
 static struct resource sb1250_mem_resource = {
        .name   = "SB1250 PCI MEM",
-       .start  = 0x14000000UL,
-       .end    = 0x17ffffffUL,
+       .start  = 0x40000000UL,
+       .end    = 0x5fffffffUL,
        .flags  = IORESOURCE_MEM,
 };
                                                                                 
 static struct resource sb1250_io_resource = {
-       .name   = "SB1250 IO MEM",
-       .start  = 0x14000000UL,
-       .end    = 0x17ffffffUL,
+       .name   = "SB1250 PCI I/O",
+       .start  = 0x00000000UL,
+       .end    = 0x01ffffffUL,
        .flags  = IORESOURCE_IO,
 };
 
 struct pci_controller sb1250_controller = {
        .pci_ops        = &sb1250_pci_ops,
        .mem_resource   = &sb1250_mem_resource,
-       .io_resource    = &sb1250_io_resource
+       .io_resource    = &sb1250_io_resource,
 };
 
 static int __init sb1250_pcibios_init(void)
@@ -208,8 +215,8 @@ static int __init sb1250_pcibios_init(void)
        /* CFE will assign PCI resources */
        pci_probe_only = 1;
 
-       /* set resource limit to avoid errors */
-       ioport_resource.end = 0x0000ffff;       /* 32MB reserved by sb1250 */
+       /* Set I/O resource limits.  */
+       ioport_resource.end = 0x01ffffff;       /* 32MB accessible by sb1250 */
        iomem_resource.end = 0xffffffff;        /* no HT support yet */
 
        cfg_space =
index c1151f4..9ab65c2 100644 (file)
@@ -3,15 +3,13 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2004 by Ralf Baechle
- *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <asm/gt64240.h>
-#include <asm/pci_channel.h>
 
 extern struct pci_ops titan_pci_ops;
 
@@ -19,19 +17,42 @@ static struct resource py_mem_resource = {
        "Titan PCI MEM", 0xe0000000UL, 0xe3ffffffUL, IORESOURCE_MEM
 };
 
+/*
+ * PMON really reserves 16MB of I/O port space but that's stupid, nothing
+ * needs that much since allocations are limited to 256 bytes per device
+ * anyway.  So we just claim 64kB here.
+ */
+#define TITAN_IO_SIZE  0x0000ffffUL
+
 static struct resource py_io_resource = {
-       "Titan IO MEM", 0x00000000UL, 0x00ffffffUL, IORESOURCE_IO,
+       "Titan IO MEM", 0x00001000UL, TITAN_IO_SIZE - 1, IORESOURCE_IO,
 };
 
 static struct pci_controller py_controller = {
        .pci_ops        = &titan_pci_ops,
        .mem_resource   = &py_mem_resource,
-       .mem_offset     = 0x10000000UL,
+       .mem_offset     = 0x00000000UL,
        .io_resource    = &py_io_resource,
        .io_offset      = 0x00000000UL
 };
 
+static char ioremap_failed[] __initdata = "Could not ioremap I/O port range";
+
 static int __init pmc_yosemite_setup(void)
 {
+       unsigned long io_v_base;
+
+       io_v_base = (unsigned long) ioremap(0xe0000000UL,TITAN_IO_SIZE);
+       if (!io_v_base)
+               panic(ioremap_failed);
+
+       set_io_port_base(io_v_base);
+
+       ioport_resource.end = TITAN_IO_SIZE - 1;
+
        register_pci_controller(&py_controller);
+
+       return 0;
 }
+
+arch_initcall(pmc_yosemite_setup);
index 08064f2..c1b659c 100644 (file)
-/*
- * Copyright 2003 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 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/linkage.h>
+#include <linux/sched.h>
+
+#include <asm/pmon.h>
+#include <asm/titan_dep.h>
+
+#define LAUNCHSTACK_SIZE 256
+
+static spinlock_t launch_lock __initdata;
+
+static unsigned long secondary_sp __initdata;
+static unsigned long secondary_gp __initdata;
+
+static unsigned char launchstack[LAUNCHSTACK_SIZE] __initdata
+       __attribute__((aligned(2 * sizeof(long))));
 
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/smp.h>
-#include <linux/kernel_stat.h>
+static void __init prom_smp_bootstrap(void)
+{
+       local_irq_disable();
 
-#include <asm/mmu_context.h>
-#include <asm/trace.h>
+       while (spin_is_locked(&launch_lock));
 
-extern void asmlinkage smp_bootstrap(void);
+       __asm__ __volatile__(
+       "       move    $sp, %0         \n"
+       "       move    $gp, %1         \n"
+       "       j       smp_bootstrap   \n"
+       :
+       : "r" (secondary_sp), "r" (secondary_gp));
+}
 
 /*
- * Send inter-processor interrupt
+ * PMON is a fragile beast.  It'll blow up once the mappings it's littering
+ * right into the middle of KSEG3 are blown away so we have to grab the slave
+ * core early and keep it in a waiting loop.
  */
-void core_send_ipi(int cpu, unsigned int action)
+void __init prom_grab_secondary(void)
 {
-        /*
-         * Generate and INTMSG so that it can be sent over to the destination CPU
-         * The INTMSG will put the STATUS bits based on the action desired
-         */
-        switch(action) {
-                case SMP_RESCHEDULE_YOURSELF:
-                        /* Do nothing */
-                        break;
-                case SMP_CALL_FUNCTION:
-                        if (cpu == 1)
-                                *(volatile uint32_t *)(0xbb000a00) = 0x00610002;
-                        else
-                                *(volatile uint32_t *)(0xbb000a00) = 0x00610001;
-                        break;
-
-                default:
-                        panic("core_send_ipi \n");
-        }
+       spin_lock(&launch_lock);
+
+       debug_vectors->cpustart(1, &prom_smp_bootstrap,
+                               launchstack + LAUNCHSTACK_SIZE, 0);
 }
 
 /*
- * Mailbox interrupt to handle IPI
+ * Detect available CPUs, populate phys_cpu_present_map before smp_init
+ *
+ * We don't want to start the secondary CPU yet nor do we have a nice probing
+ * feature in PMON so we just assume presence of the secondary core.
  */
-void jaguar_mailbox_irq(struct pt_regs *regs)
+void prom_prepare_cpus(unsigned int max_cpus)
 {
-        int cpu = smp_processor_id();
+       cpus_clear(phys_cpu_present_map);
+
+       /*
+        * The boot CPU
+        */
+       cpu_set(0, phys_cpu_present_map);
+       __cpu_number_map[0]     = 0;
+       __cpu_logical_map[0]    = 0;
+
+       /*
+        * The secondary core
+        */
+       cpu_set(1, phys_cpu_present_map);
+       __cpu_number_map[1]     = 1;
+       __cpu_logical_map[1]    = 1;
+}
 
-        /* SMP_CALL_FUNCTION */
-        smp_call_function_interrupt();
+/*
+ * Firmware CPU startup hook
+ * Complicated by PMON's weird interface which tries to minimic the UNIX fork.
+ * It launches the next * available CPU and copies some information on the
+ * stack so the first thing we do is throw away that stuff and load useful
+ * values into the registers ...
+ */
+void prom_boot_secondary(int cpu, struct task_struct *idle)
+{
+       unsigned long gp = (unsigned long) idle->thread_info;
+       unsigned long sp = gp + THREAD_SIZE - 32;
+
+       secondary_sp = sp;
+       secondary_gp = gp;
+
+       spin_unlock(&launch_lock);
+}
+
+/* Hook for after all CPUs are online */
+void prom_cpus_done(void)
+{
 }
 
-extern atomic_t cpus_booted;
+/*
+ *  After we've done initial boot, this function is called to allow the
+ *  board code to clean up state, if needed
+ */
+void prom_init_secondary(void)
+{
+       set_c0_status(ST0_CO | ST0_IE | ST0_IM);
+}
 
-void __init start_secondary(void)
+void prom_smp_finish(void)
 {
-        unsigned int cpu = smp_processor_id();
-        extern atomic_t smp_commenced;
-
-        if (current->processor != 1) {
-                printk("Impossible CPU %d \n", cpu);
-                current->processor = 1;
-                current->cpus_runnable = 1 << 1;
-                cpu = current->processor;
-        }
-
-        if (current->mm)
-                current->mm = NULL;
-
-        prom_init_secondary();
-        per_cpu_trap_init();
-
-        /*
-         * XXX parity protection should be folded in here when it's converted
-         * to an option instead of something based on .cputype
-         */
-        pgd_current[cpu] = init_mm.pgd;
-        cpu_data[cpu].udelay_val = loops_per_jiffy;
-        prom_smp_finish();
-        CPUMASK_SETB(cpu_online_map, cpu);
-        atomic_inc(&cpus_booted);
-        __flush_cache_all();
-
-        printk("Slave cpu booted successfully  \n");
-        *(volatile uint32_t *)(0xbb000a68) = 0x00000000;
-        *(volatile uint32_t *)(0xbb000a68) = 0x80000000;
-
-        while (*(volatile uint32_t *)(0xbb000a68) != 0x00000000);
-
-        return cpu_idle();
 }
 
-void __init smp_boot_cpus(void)
+asmlinkage void titan_mailbox_irq(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+       unsigned long status;
+
+       if (cpu == 0) {
+               status = OCD_READ(RM9000x2_OCD_INTP0STATUS3);
+               OCD_WRITE(RM9000x2_OCD_INTP0CLEAR3, status);
+       }
+
+       if (cpu == 1) {
+               status = OCD_READ(RM9000x2_OCD_INTP1STATUS3);
+               OCD_WRITE(RM9000x2_OCD_INTP1CLEAR3, status);
+       }
+
+       if (status & 0x2)
+               smp_call_function_interrupt();
+}
+
+/*
+ * Send inter-processor interrupt
+ */
+void core_send_ipi(int cpu, unsigned int action)
 {
-        int i;
-        int cur_cpu = 0;
-
-        smp_num_cpus = prom_setup_smp();
-        printk("Detected %d available CPUs \n", smp_num_cpus);
-
-        init_new_context(current, &init_mm);
-        current->processor = 0;
-        cpu_data[0].udelay_val = loops_per_jiffy;
-        cpu_data[0].asid_cache = ASID_FIRST_VERSION;
-        CPUMASK_CLRALL(cpu_online_map);
-        CPUMASK_SETB(cpu_online_map, 0);
-        atomic_set(&cpus_booted, 1);  /* Master CPU is already booted... */
-        init_idle();
-
-        __cpu_number_map[0] = 0;
-        __cpu_logical_map[0] = 0;
-
-        /*
-         * This loop attempts to compensate for "holes" in the CPU
-         * numbering.  It's overkill, but general.
-         */
-        for (i = 1; i < smp_num_cpus; ) {
-                struct task_struct *p;
-                struct pt_regs regs;
-                int retval;
-                printk("Starting CPU %d... \n", i);
-
-                /* Spawn a new process normally.  Grab a pointer to
-                   its task struct so we can mess with it */
-                do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
-
-                p = init_task.prev_task;
-                if (!p)
-                        panic("failed fork for CPU %d", i);
-
-                /* This is current for the second processor */
-                p->processor = i;
-                p->cpus_runnable = 1 << i; /* we schedule the first task manually */
-                p->thread.reg31 = (unsigned long) start_secondary;
-
-                del_from_runqueue(p);
-                unhash_process(p);
-                init_tasks[i] = p;
-
-                __flush_cache_all();
-
-                do {
-                        /* Iterate until we find a CPU that comes up */
-                        cur_cpu++;
-                        retval = prom_boot_secondary(cur_cpu,
-                                            (unsigned long)p + KERNEL_STACK_SIZE - 32,
-                                            (unsigned long)p);
-
-                } while (!retval && (cur_cpu < NR_CPUS));
-                if (retval) {
-                        __cpu_number_map[cur_cpu] = i;
-                        __cpu_logical_map[i] = cur_cpu;
-                        i++;
-                } else {
-                        panic("CPU discovery disaster");
-                }
-        }
-
-        /* Local semaphore to both the CPUs */
-
-        *(volatile uint32_t *)(0xbb000a68) = 0x80000000;
-        while (*(volatile uint32_t *)(0xbb000a68) != 0x00000000);
-
-        smp_threads_ready = 1;
+       /*
+        * Generate an INTMSG so that it can be sent over to the
+        * destination CPU. The INTMSG will put the STATUS bits
+        * based on the action desired. An alternative strategy
+        * is to write to the Interrupt Set register, read the
+        * Interrupt Status register and clear the Interrupt
+        * Clear register. The latter is preffered.
+        */
+       switch (action) {
+       case SMP_RESCHEDULE_YOURSELF:
+               if (cpu == 1)
+                       OCD_WRITE(RM9000x2_OCD_INTP1SET3, 4);
+               else
+                       OCD_WRITE(RM9000x2_OCD_INTP0SET3, 4);
+               break;
+
+       case SMP_CALL_FUNCTION:
+               if (cpu == 1)
+                       OCD_WRITE(RM9000x2_OCD_INTP1SET3, 2);
+               else
+                       OCD_WRITE(RM9000x2_OCD_INTP0SET3, 2);
+               break;
+       }
 }
index 943c942..a28dc78 100644 (file)
@@ -65,7 +65,7 @@ static void print_buserr(void)
                        cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "",
                        cpu_err_addr);
        if (gio_err_stat & GIO_ERRMASK)
-               printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x08%x\n",
+               printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n",
                        gio_err_stat,
                        gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "",
                        gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "",
index acb44a1..ea2844d 100644 (file)
@@ -309,7 +309,7 @@ static struct irqaction map1_cascade = {
 
 extern void mips_cpu_irq_init(unsigned int irq_base);
 
-void __init init_IRQ(void)
+void __init arch_init_irq(void)
 {
        int i;
 
@@ -371,7 +371,6 @@ void __init init_IRQ(void)
 
        set_except_vector(0, indyIRQ);
 
-       init_generic_irq();
        /* init CPU irqs */
        mips_cpu_irq_init(SGINT_CPU);
 
index b8ee02c..f624f9d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sched.h>
 #include <linux/mmzone.h>      /* for numnodes */
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/cpumask.h>
 #include <asm/cpu.h>
 #include <asm/io.h>
 #define CPU_NONE               (cpuid_t)-1
 
 static DECLARE_BITMAP(hub_init_mask, MAX_COMPACT_NODES);
-static hubreg_t region_mask;
-static int     fine_mode;
-static int router_distance;
 nasid_t master_nasid = INVALID_NASID;
 
 cnodeid_t      nasid_to_compact_node[MAX_NASIDS];
 nasid_t                compact_to_nasid_node[MAX_COMPACT_NODES];
 cnodeid_t      cpuid_to_compact_node[MAXCPUS];
-char           node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
 
-static hubreg_t get_region(cnodeid_t cnode)
-{
-       if (fine_mode)
-               return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
-       else
-               return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
-}
-
-static void gen_region_mask(hubreg_t *region_mask, int maxnodes)
-{
-       cnodeid_t cnode;
-
-       (*region_mask) = 0;
-       for (cnode = 0; cnode < maxnodes; cnode++) {
-               (*region_mask) |= 1ULL << get_region(cnode);
-       }
-}
-
-static int is_fine_dirmode(void)
-{
-       return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK)
-               >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE);
-}
+EXPORT_SYMBOL(nasid_to_compact_node);
 
 extern void pcibr_setup(cnodeid_t);
 
-static __init void per_slice_init(cnodeid_t cnode, int slice)
-{
-       struct slice_data *si = hub_data[cnode]->slice + slice;
-       int cpu = smp_processor_id();
-       int i;
-
-       for (i = 0; i < LEVELS_PER_SLICE; i++)
-               si->level_to_irq[i] = -1;
-       /*
-        * Some interrupts are reserved by hardware or by software convention.
-        * Mark these as reserved right away so they won't be used accidently
-        * later.
-        */
-       for (i = 0; i <= BASE_PCI_IRQ; i++) {
-               __set_bit(i, si->irq_alloc_mask);
-               LOCAL_HUB_S(PI_INT_PEND_MOD, i);
-       }
-
-       __set_bit(IP_PEND0_6_63, si->irq_alloc_mask);
-       LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63);
-
-       for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) {
-               __set_bit(i, si->irq_alloc_mask + 1);
-               LOCAL_HUB_S(PI_INT_PEND_MOD, i);
-       }
-
-       LOCAL_HUB_L(PI_INT_PEND0);
-
-       /*
-        * We use this so we can find the local hub's data as fast as only
-        * possible.
-        */
-       cpu_data[cpu].data = si;
-}
-
 extern void xtalk_probe_node(cnodeid_t nid);
 
-void __init per_hub_init(cnodeid_t cnode)
+static void __init per_hub_init(cnodeid_t cnode)
 {
-       struct hub_data *hub = HUB_DATA(cnode);
+       struct hub_data *hub = hub_data(cnode);
        nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
-       int slice = LOCAL_HUB_L(PI_CPU_NUM);
 
        cpu_set(smp_processor_id(), hub->h_cpus);
 
-       if (!test_and_set_bit(slice, &hub->slice_map))
-               per_slice_init(cnode, slice);
-
        if (test_and_set_bit(cnode, hub_init_mask))
                return;
 
@@ -142,13 +78,13 @@ void __init per_hub_init(cnodeid_t cnode)
         * copy over the caliased exception handlers.
         */
        if (get_compact_nodeid() == cnode) {
-               extern char except_vec0, except_vec1_r10k;
+               extern char except_vec0, except_vec1_r4k;
                extern char except_vec2_generic, except_vec3_generic;
 
                memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80);
                memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x80);
                memcpy((void *)KSEG0, &except_vec0, 0x80);
-               memcpy((void *)KSEG0 + 0x080, &except_vec1_r10k, 0x80);
+               memcpy((void *)KSEG0 + 0x080, &except_vec1_r4k, 0x80);
                memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80);
                memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x100);
                __flush_cache_all();
@@ -156,260 +92,76 @@ void __init per_hub_init(cnodeid_t cnode)
 #endif
 }
 
-/*
- * get_nasid() returns the physical node id number of the caller.
- */
-nasid_t
-get_nasid(void)
-{
-       return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK)
-                        >> NSRI_NODEID_SHFT);
-}
-
-/*
- * Map the physical node id to a virtual node id (virtual node ids are contiguous).
- */
-cnodeid_t get_compact_nodeid(void)
-{
-       return NASID_TO_COMPACT_NODEID(get_nasid());
-}
-
-#define        rou_rflag       rou_flags
-
-static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
+void __init per_cpu_init(void)
 {
-       klrou_t *router;
-       lboard_t *brd;
-       int     port;
-
-       if (router_a->rou_rflag == 1)
-               return;
+       int cpu = smp_processor_id();
+       int slice = LOCAL_HUB_L(PI_CPU_NUM);
+       cnodeid_t cnode = get_compact_nodeid();
+       struct hub_data *hub = hub_data(cnode);
+       struct slice_data *si = hub->slice + slice;
+       int i;
 
-       if (depth >= router_distance)
+       if (test_and_set_bit(slice, &hub->slice_map))
                return;
 
-       router_a->rou_rflag = 1;
-
-       for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
-               if (router_a->rou_port[port].port_nasid == INVALID_NASID)
-                       continue;
-
-               brd = (lboard_t *)NODE_OFFSET_TO_K0(
-                       router_a->rou_port[port].port_nasid,
-                       router_a->rou_port[port].port_offset);
-
-               if (brd->brd_type == KLTYPE_ROUTER) {
-                       router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
-                       if (router == router_b) {
-                               if (depth < router_distance)
-                                       router_distance = depth;
-                       }
-                       else
-                               router_recurse(router, router_b, depth + 1);
-               }
-       }
-
-       router_a->rou_rflag = 0;
-}
-
-int node_distance(nasid_t nasid_a, nasid_t nasid_b)
-{
-       klrou_t *router, *router_a = NULL, *router_b = NULL;
-       lboard_t *brd, *dest_brd;
-       cnodeid_t cnode;
-       nasid_t nasid;
-       int port;
-
-       /* Figure out which routers nodes in question are connected to */
-       for (cnode = 0; cnode < numnodes; cnode++) {
-               nasid = COMPACT_TO_NASID_NODEID(cnode);
-
-               if (nasid == -1) continue;
-
-               brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
-                                       KLTYPE_ROUTER);
-
-               if (!brd)
-                       continue;
-
-               do {
-                       if (brd->brd_flags & DUPLICATE_BOARD)
-                               continue;
-
-                       router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
-                       router->rou_rflag = 0;
+       clear_c0_status(ST0_IM);
 
-                       for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
-                               if (router->rou_port[port].port_nasid == INVALID_NASID)
-                                       continue;
+       for (i = 0; i < LEVELS_PER_SLICE; i++)
+               si->level_to_irq[i] = -1;
 
-                               dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
-                                       router->rou_port[port].port_nasid,
-                                       router->rou_port[port].port_offset);
+       /*
+        * Some interrupts are reserved by hardware or by software convention.
+        * Mark these as reserved right away so they won't be used accidently
+        * later.
+        */
+       for (i = 0; i <= BASE_PCI_IRQ; i++) {
+               __set_bit(i, si->irq_alloc_mask);
+               LOCAL_HUB_S(PI_INT_PEND_MOD, i);
+       }
 
-                               if (dest_brd->brd_type == KLTYPE_IP27) {
-                                       if (dest_brd->brd_nasid == nasid_a)
-                                               router_a = router;
-                                       if (dest_brd->brd_nasid == nasid_b)
-                                               router_b = router;
-                               }
-                       }
+       __set_bit(IP_PEND0_6_63, si->irq_alloc_mask);
+       LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63);
 
-               } while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
+       for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) {
+               __set_bit(i, si->irq_alloc_mask + 1);
+               LOCAL_HUB_S(PI_INT_PEND_MOD, i);
        }
 
-       if (router_a == NULL) {
-               printk("node_distance: router_a NULL\n");
-               return -1;
-       }
-       if (router_b == NULL) {
-               printk("node_distance: router_b NULL\n");
-               return -1;
-       }
+       LOCAL_HUB_L(PI_INT_PEND0);
 
-       if (nasid_a == nasid_b)
-               return 0;
+       /*
+        * We use this so we can find the local hub's data as fast as only
+        * possible.
+        */
+       cpu_data[cpu].data = si;
 
-       if (router_a == router_b)
-               return 1;
+       cpu_time_init();
+       install_ipi();
 
-       router_distance = 100;
-       router_recurse(router_a, router_b, 2);
+       /* Install our NMI handler if symmon hasn't installed one. */
+       install_cpu_nmi_handler(cputoslice(cpu));
 
-       return router_distance;
-}
+       set_c0_status(SRB_DEV0 | SRB_DEV1);
 
-static void init_topology_matrix(void)
-{
-       nasid_t nasid, nasid2;
-       cnodeid_t row, col;
-
-       for (row = 0; row < MAX_COMPACT_NODES; row++)
-               for (col = 0; col < MAX_COMPACT_NODES; col++)
-                       node_distances[row][col] = -1;
-
-       for (row = 0; row < numnodes; row++) {
-               nasid = COMPACT_TO_NASID_NODEID(row);
-               for (col = 0; col < numnodes; col++) {
-                       nasid2 = COMPACT_TO_NASID_NODEID(col);
-                       node_distances[row][col] = node_distance(nasid, nasid2);
-               }
-       }
+       per_hub_init(cnode);
 }
 
-static void dump_topology(void)
+/*
+ * get_nasid() returns the physical node id number of the caller.
+ */
+nasid_t
+get_nasid(void)
 {
-       nasid_t nasid;
-       cnodeid_t cnode;
-       lboard_t *brd, *dest_brd;
-       int port;
-       int router_num = 0;
-       klrou_t *router;
-       cnodeid_t row, col;
-
-       printk("************** Topology ********************\n");
-
-       printk("    ");
-       for (col = 0; col < numnodes; col++)
-               printk("%02d ", col);
-       printk("\n");
-       for (row = 0; row < numnodes; row++) {
-               printk("%02d  ", row);
-               for (col = 0; col < numnodes; col++)
-                       printk("%2d ", node_distances[row][col]);
-               printk("\n");
-       }
-
-       for (cnode = 0; cnode < numnodes; cnode++) {
-               nasid = COMPACT_TO_NASID_NODEID(cnode);
-
-               if (nasid == -1) continue;
-
-               brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
-                                       KLTYPE_ROUTER);
-
-               if (!brd)
-                       continue;
-
-               do {
-                       if (brd->brd_flags & DUPLICATE_BOARD)
-                               continue;
-                       printk("Router %d:", router_num);
-                       router_num++;
-
-                       router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
-
-                       for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
-                               if (router->rou_port[port].port_nasid == INVALID_NASID)
-                                       continue;
-
-                               dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
-                                       router->rou_port[port].port_nasid,
-                                       router->rou_port[port].port_offset);
-
-                               if (dest_brd->brd_type == KLTYPE_IP27)
-                                       printk(" %d", dest_brd->brd_nasid);
-                               if (dest_brd->brd_type == KLTYPE_ROUTER)
-                                       printk(" r");
-                       }
-                       printk("\n");
-
-               } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
-       }
+       return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK)
+                        >> NSRI_NODEID_SHFT);
 }
 
-void mlreset(void)
+/*
+ * Map the physical node id to a virtual node id (virtual node ids are contiguous).
+ */
+cnodeid_t get_compact_nodeid(void)
 {
-       int i;
-
-       master_nasid = get_nasid();
-       fine_mode = is_fine_dirmode();
-
-       /*
-        * Probe for all CPUs - this creates the cpumask and sets up the
-        * mapping tables.  We need to do this as early as possible.
-        */
-#ifdef CONFIG_SMP
-       cpu_node_probe();
-#endif
-
-       init_topology_matrix();
-       dump_topology();
-
-       gen_region_mask(&region_mask, numnodes);
-
-       setup_replication_mask(numnodes);
-
-       /*
-        * Set all nodes' calias sizes to 8k
-        */
-       for (i = 0; i < numnodes; i++) {
-               nasid_t nasid;
-
-               nasid = COMPACT_TO_NASID_NODEID(i);
-
-               /*
-                * Always have node 0 in the region mask, otherwise
-                * CALIAS accesses get exceptions since the hub
-                * thinks it is a node 0 address.
-                */
-               REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
-#ifdef CONFIG_REPLICATE_EXHANDLERS
-               REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
-#else
-               REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
-#endif
-
-#ifdef LATER
-               /*
-                * Set up all hubs to have a big window pointing at
-                * widget 0. Memory mode, widget 0, offset 0
-                */
-               REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
-                       ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
-                       (0 << IIO_ITTE_WIDGET_SHIFT)));
-#endif
-       }
+       return NASID_TO_COMPACT_NODEID(get_nasid());
 }
 
 /* Extracted from the IOC3 meta driver.  FIXME.  */
@@ -444,20 +196,6 @@ static inline void ioc3_eth_init(void)
        ioc3->eier = 0;
 }
 
-void __init per_cpu_init(void)
-{
-       cnodeid_t cnode = get_compact_nodeid();
-       int cpu = smp_processor_id();
-
-       clear_c0_status(ST0_IM);
-       per_hub_init(cnode);
-       cpu_time_init();
-       install_ipi();
-       /* Install our NMI handler if symmon hasn't installed one. */
-       install_cpu_nmi_handler(cputoslice(cpu));
-       set_c0_status(SRB_DEV0 | SRB_DEV1);
-}
-
 extern void ip27_setup_console(void);
 extern void ip27_time_init(void);
 extern void ip27_reboot_setup(void);
index 917c1ee..61817a1 100644 (file)
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/irq.h>
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp_lock.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
@@ -151,9 +152,6 @@ void ip27_do_irq_mask0(struct pt_regs *regs)
        if (!pend0)
                return;
 
-       /* Prevent any of the picked intrs from recursing */
-       LOCAL_HUB_S(pi_int_mask0, mask0 & ~pend0);
-
        swlevel = ms1bit(pend0);
 #ifdef CONFIG_SMP
        if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) {
@@ -176,11 +174,6 @@ void ip27_do_irq_mask0(struct pt_regs *regs)
                do_IRQ(irq, regs);
        }
 
-       /* clear bit in pend0 */
-       pend0 ^= 1UL << swlevel;
-
-       /* Now allow the set of serviced intrs again */
-       LOCAL_HUB_S(pi_int_mask0, mask0);
        LOCAL_HUB_L(PI_INT_PEND0);
 }
 
@@ -200,19 +193,12 @@ void ip27_do_irq_mask1(struct pt_regs *regs)
        if (!pend1)
                return;
 
-       /* Prevent any of the picked intrs from recursing */
-       LOCAL_HUB_S(pi_int_mask1, mask1 & ~pend1);
-
        swlevel = ms1bit(pend1);
        /* "map" swlevel to irq */
        irq = si->level_to_irq[swlevel];
        LOCAL_HUB_CLR_INTR(swlevel);
        do_IRQ(irq, regs);
-       /* clear bit in pend1 */
-       pend1 ^= 1UL << swlevel;
 
-       /* Now allow the set of serviced intrs again */
-       LOCAL_HUB_S(pi_int_mask1, mask1);
        LOCAL_HUB_L(PI_INT_PEND1);
 }
 
@@ -233,9 +219,6 @@ static int intr_connect_level(int cpu, int bit)
 
        __set_bit(bit, si->irq_enable_mask);
 
-       /* Make sure it's not already pending when we connect it. */
-       REMOTE_HUB_CLR_INTR(nasid, bit);
-
        if (!cputoslice(cpu)) {
                REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
                REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
@@ -272,6 +255,7 @@ static unsigned int startup_bridge_irq(unsigned int irq)
        bridgereg_t device;
        bridge_t *bridge;
        int pin, swlevel;
+       cpuid_t cpu;
 
        pin = SLOT_FROM_PCI_IRQ(irq);
        bc = IRQ_TO_BRIDGE(irq);
@@ -282,13 +266,10 @@ static unsigned int startup_bridge_irq(unsigned int irq)
         * "map" irq to a swlevel greater than 6 since the first 6 bits
         * of INT_PEND0 are taken
         */
-       swlevel = alloc_level(bc->irq_cpu, irq);
-       intr_connect_level(bc->irq_cpu, swlevel);
-
+       swlevel = find_level(&cpu, irq);
        bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8));
        bridge->b_int_enable |= (1 << pin);
-       /* more stuff in int_enable reg */
-       bridge->b_int_enable |= 0x7ffffe00;
+       bridge->b_int_enable |= 0x7ffffe00;     /* more stuff in int_enable */
 
        /*
         * Enable sending of an interrupt clear packt to the hub on a high to
@@ -308,7 +289,7 @@ static unsigned int startup_bridge_irq(unsigned int irq)
        device |= (pin << (pin*3));
        bridge->b_int_device = device;
 
-        bridge->b_widget.w_tflush;                      /* Flush */
+        bridge->b_wid_tflush;
 
         return 0;       /* Never anything pending.  */
 }
@@ -336,26 +317,37 @@ static void shutdown_bridge_irq(unsigned int irq)
        si->level_to_irq[swlevel] = -1;
 
        bridge->b_int_enable &= ~(1 << pin);
-       bridge->b_widget.w_tflush;                      /* Flush */
+       bridge->b_wid_tflush;
 }
 
 static inline void enable_bridge_irq(unsigned int irq)
 {
-       /* All the braindamage happens magically for us in ip27_do_irq */
+       cpuid_t cpu;
+       int swlevel;
+
+       swlevel = find_level(&cpu, irq);        /* Criminal offence */
+       intr_connect_level(cpu, swlevel);
 }
 
-static void disable_bridge_irq(unsigned int irq)
+static inline void disable_bridge_irq(unsigned int irq)
 {
-       /* All the braindamage happens magically for us in ip27_do_irq */
+       cpuid_t cpu;
+       int swlevel;
+
+       swlevel = find_level(&cpu, irq);        /* Criminal offence */
+       intr_disconnect_level(cpu, swlevel);
 }
 
 static void mask_and_ack_bridge_irq(unsigned int irq)
 {
-       /* All the braindamage happens magically for us in ip27_do_irq */
+       disable_bridge_irq(irq);
 }
 
 static void end_bridge_irq(unsigned int irq)
 {
+       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
+           irq_desc[irq].action)
+               enable_bridge_irq(irq);
 }
 
 static struct hw_interrupt_type bridge_irq_type = {
@@ -370,15 +362,15 @@ static struct hw_interrupt_type bridge_irq_type = {
 
 static unsigned long irq_map[NR_IRQS / BITS_PER_LONG];
 
-unsigned int allocate_irqno(void)
+static int allocate_irqno(void)
 {
        int irq;
 
 again:
-       irq = find_first_zero_bit(irq_map, LEVELS_PER_SLICE);
+       irq = find_first_zero_bit(irq_map, NR_IRQS);
 
        if (irq >= NR_IRQS)
-               return -1;
+               return -ENOSPC;
 
        if (test_and_set_bit(irq, irq_map))
                goto again;
@@ -391,21 +383,49 @@ void free_irqno(unsigned int irq)
        clear_bit(irq, irq_map);
 }
 
-void __init init_IRQ(void)
+void __devinit register_bridge_irq(unsigned int irq)
 {
-       int i;
+       irq_desc[irq].status    = IRQ_DISABLED;
+       irq_desc[irq].action    = 0;
+       irq_desc[irq].depth     = 1;
+       irq_desc[irq].handler   = &bridge_irq_type;
+}
 
-       set_except_vector(0, ip27_irq);
+int __devinit request_bridge_irq(struct bridge_controller *bc)
+{
+       int irq = allocate_irqno();
+       int swlevel, cpu;
+       nasid_t nasid;
+
+       if (irq < 0)
+               return irq;
 
        /*
-        * Right now the bridge irq is our kitchen sink interrupt type
+        * "map" irq to a swlevel greater than 6 since the first 6 bits
+        * of INT_PEND0 are taken
         */
-       for (i = 0; i <= NR_IRQS; i++) {
-               irq_desc[i].status      = IRQ_DISABLED;
-               irq_desc[i].action      = 0;
-               irq_desc[i].depth       = 1;
-               irq_desc[i].handler     = &bridge_irq_type;
+       cpu = bc->irq_cpu;
+       swlevel = alloc_level(cpu, irq);
+       if (unlikely(swlevel < 0)) {
+               free_irqno(irq);
+
+               return -EAGAIN;
        }
+
+       /* Make sure it's not already pending when we connect it. */
+       nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
+       REMOTE_HUB_CLR_INTR(nasid, swlevel);
+
+       intr_connect_level(cpu, swlevel);
+
+       register_bridge_irq(irq);
+
+       return irq;
+}
+
+void __init arch_init_irq(void)
+{
+       set_except_vector(0, ip27_irq);
 }
 
 void install_ipi(void)
index b5e86ad..fb47c75 100644 (file)
@@ -61,12 +61,12 @@ void __init setup_replication_mask(int maxnodes)
 
 static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid)
 {
-       kern_vars_t *kvp;
        cnodeid_t client_cnode;
+       kern_vars_t *kvp;
 
        client_cnode = NASID_TO_COMPACT_NODEID(client_nasid);
 
-       kvp = &(HUB_DATA(client_nasid)->kern_vars);
+       kvp = &hub_data(client_nasid)->kern_vars;
 
        KERN_VARS_ADDR(client_nasid) = (unsigned long)kvp;
 
index e3cdb95..327eadb 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
+#include <linux/module.h>
 #include <linux/swap.h>
 #include <linux/bootmem.h>
 #include <asm/page.h>
@@ -36,8 +37,226 @@ static short __initdata slot_lastfilled_cache[MAX_COMPACT_NODES];
 static unsigned short __initdata slot_psize_cache[MAX_COMPACT_NODES][MAX_MEM_SLOTS];
 static struct bootmem_data __initdata plat_node_bdata[MAX_COMPACT_NODES];
 
-struct pglist_data *node_data[MAX_COMPACT_NODES];
-struct hub_data *hub_data[MAX_COMPACT_NODES];
+struct node_data *__node_data[MAX_COMPACT_NODES];
+
+EXPORT_SYMBOL(__node_data);
+
+static int fine_mode;
+
+static int is_fine_dirmode(void)
+{
+       return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK)
+               >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE);
+}
+
+static hubreg_t get_region(cnodeid_t cnode)
+{
+       if (fine_mode)
+               return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
+       else
+               return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
+}
+
+static hubreg_t region_mask;
+
+static void gen_region_mask(hubreg_t *region_mask, int maxnodes)
+{
+       cnodeid_t cnode;
+
+       (*region_mask) = 0;
+       for (cnode = 0; cnode < maxnodes; cnode++) {
+               (*region_mask) |= 1ULL << get_region(cnode);
+       }
+}
+
+#define        rou_rflag       rou_flags
+
+static int router_distance;
+
+static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
+{
+       klrou_t *router;
+       lboard_t *brd;
+       int     port;
+
+       if (router_a->rou_rflag == 1)
+               return;
+
+       if (depth >= router_distance)
+               return;
+
+       router_a->rou_rflag = 1;
+
+       for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+               if (router_a->rou_port[port].port_nasid == INVALID_NASID)
+                       continue;
+
+               brd = (lboard_t *)NODE_OFFSET_TO_K0(
+                       router_a->rou_port[port].port_nasid,
+                       router_a->rou_port[port].port_offset);
+
+               if (brd->brd_type == KLTYPE_ROUTER) {
+                       router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
+                       if (router == router_b) {
+                               if (depth < router_distance)
+                                       router_distance = depth;
+                       }
+                       else
+                               router_recurse(router, router_b, depth + 1);
+               }
+       }
+
+       router_a->rou_rflag = 0;
+}
+
+unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
+
+static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
+{
+       klrou_t *router, *router_a = NULL, *router_b = NULL;
+       lboard_t *brd, *dest_brd;
+       cnodeid_t cnode;
+       nasid_t nasid;
+       int port;
+
+       /* Figure out which routers nodes in question are connected to */
+       for (cnode = 0; cnode < numnodes; cnode++) {
+               nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+               if (nasid == -1) continue;
+
+               brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+                                       KLTYPE_ROUTER);
+
+               if (!brd)
+                       continue;
+
+               do {
+                       if (brd->brd_flags & DUPLICATE_BOARD)
+                               continue;
+
+                       router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
+                       router->rou_rflag = 0;
+
+                       for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+                               if (router->rou_port[port].port_nasid == INVALID_NASID)
+                                       continue;
+
+                               dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+                                       router->rou_port[port].port_nasid,
+                                       router->rou_port[port].port_offset);
+
+                               if (dest_brd->brd_type == KLTYPE_IP27) {
+                                       if (dest_brd->brd_nasid == nasid_a)
+                                               router_a = router;
+                                       if (dest_brd->brd_nasid == nasid_b)
+                                               router_b = router;
+                               }
+                       }
+
+               } while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
+       }
+
+       if (router_a == NULL) {
+               printk("node_distance: router_a NULL\n");
+               return -1;
+       }
+       if (router_b == NULL) {
+               printk("node_distance: router_b NULL\n");
+               return -1;
+       }
+
+       if (nasid_a == nasid_b)
+               return 0;
+
+       if (router_a == router_b)
+               return 1;
+
+       router_distance = 100;
+       router_recurse(router_a, router_b, 2);
+
+       return router_distance;
+}
+
+static void __init init_topology_matrix(void)
+{
+       nasid_t nasid, nasid2;
+       cnodeid_t row, col;
+
+       for (row = 0; row < MAX_COMPACT_NODES; row++)
+               for (col = 0; col < MAX_COMPACT_NODES; col++)
+                       __node_distances[row][col] = -1;
+
+       for (row = 0; row < numnodes; row++) {
+               nasid = COMPACT_TO_NASID_NODEID(row);
+               for (col = 0; col < numnodes; col++) {
+                       nasid2 = COMPACT_TO_NASID_NODEID(col);
+                       __node_distances[row][col] =
+                               compute_node_distance(nasid, nasid2);
+               }
+       }
+}
+
+static void __init dump_topology(void)
+{
+       nasid_t nasid;
+       cnodeid_t cnode;
+       lboard_t *brd, *dest_brd;
+       int port;
+       int router_num = 0;
+       klrou_t *router;
+       cnodeid_t row, col;
+
+       printk("************** Topology ********************\n");
+
+       printk("    ");
+       for (col = 0; col < numnodes; col++)
+               printk("%02d ", col);
+       printk("\n");
+       for (row = 0; row < numnodes; row++) {
+               printk("%02d  ", row);
+               for (col = 0; col < numnodes; col++)
+                       printk("%2d ", node_distance(row, col));
+               printk("\n");
+       }
+
+       for (cnode = 0; cnode < numnodes; cnode++) {
+               nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+               if (nasid == -1) continue;
+
+               brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+                                       KLTYPE_ROUTER);
+
+               if (!brd)
+                       continue;
+
+               do {
+                       if (brd->brd_flags & DUPLICATE_BOARD)
+                               continue;
+                       printk("Router %d:", router_num);
+                       router_num++;
+
+                       router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
+
+                       for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+                               if (router->rou_port[port].port_nasid == INVALID_NASID)
+                                       continue;
+
+                               dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+                                       router->rou_port[port].port_nasid,
+                                       router->rou_port[port].port_offset);
+
+                               if (dest_brd->brd_type == KLTYPE_IP27)
+                                       printk(" %d", dest_brd->brd_nasid);
+                               if (dest_brd->brd_type == KLTYPE_ROUTER)
+                                       printk(" r");
+                       }
+                       printk("\n");
+
+               } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
+       }
+}
 
 static pfn_t __init slot_getbasepfn(cnodeid_t cnode, int slot)
 {
@@ -126,6 +345,60 @@ static pfn_t __init slot_psize_compute(cnodeid_t node, int slot)
        }
 }
 
+static void __init mlreset(void)
+{
+       int i;
+
+       master_nasid = get_nasid();
+       fine_mode = is_fine_dirmode();
+
+       /*
+        * Probe for all CPUs - this creates the cpumask and sets up the
+        * mapping tables.  We need to do this as early as possible.
+        */
+#ifdef CONFIG_SMP
+       cpu_node_probe();
+#endif
+
+       init_topology_matrix();
+       dump_topology();
+
+       gen_region_mask(&region_mask, numnodes);
+
+       setup_replication_mask(numnodes);
+
+       /*
+        * Set all nodes' calias sizes to 8k
+        */
+       for (i = 0; i < numnodes; i++) {
+               nasid_t nasid;
+
+               nasid = COMPACT_TO_NASID_NODEID(i);
+
+               /*
+                * Always have node 0 in the region mask, otherwise
+                * CALIAS accesses get exceptions since the hub
+                * thinks it is a node 0 address.
+                */
+               REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
+#ifdef CONFIG_REPLICATE_EXHANDLERS
+               REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
+#else
+               REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
+#endif
+
+#ifdef LATER
+               /*
+                * Set up all hubs to have a big window pointing at
+                * widget 0. Memory mode, widget 0, offset 0
+                */
+               REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
+                       ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
+                       (0 << IIO_ITTE_WIDGET_SHIFT)));
+#endif
+       }
+}
+
 static void __init szmem(void)
 {
        pfn_t slot_psize, slot0sz = 0, nodebytes;       /* Hack to detect problem configs */
@@ -164,6 +437,45 @@ static void __init szmem(void)
        }
 }
 
+static void __init node_mem_init(cnodeid_t node)
+{
+       pfn_t slot_firstpfn = slot_getbasepfn(node, 0);
+       pfn_t slot_lastpfn = slot_firstpfn + slot_getsize(node, 0);
+       pfn_t slot_freepfn = node_getfirstfree(node);
+       struct pglist_data *pd;
+       unsigned long bootmap_size;
+
+       /*
+        * Allocate the node data structures on the node first.
+        */
+       __node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
+
+       pd = NODE_DATA(node);
+       pd->bdata = &plat_node_bdata[node];
+
+       cpus_clear(hub_data(node)->h_cpus);
+
+       slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
+                              sizeof(struct hub_data));
+
+       bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn,
+                                       slot_firstpfn, slot_lastpfn);
+       free_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
+                       (slot_lastpfn - slot_firstpfn) << PAGE_SHIFT);
+       reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
+               ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size);
+}
+
+/*
+ * A node with nothing.  We use it to avoid any special casing in
+ * node_to_cpumask
+ */
+static struct node_data null_node = {
+       .hub = {
+               .h_cpus = CPU_MASK_NONE
+       }
+};
+
 /*
  * Currently, the intranode memory hole support assumes that each slot
  * contains at least 32 MBytes of memory. We assume all bootmem data
@@ -176,31 +488,12 @@ void __init prom_meminit(void)
        mlreset();
        szmem();
 
-       for (node = 0; node < numnodes; node++) {
-               pfn_t slot_firstpfn = slot_getbasepfn(node, 0);
-               pfn_t slot_lastpfn = slot_firstpfn + slot_getsize(node, 0);
-               pfn_t slot_freepfn = node_getfirstfree(node);
-               unsigned long bootmap_size;
-
-               /*
-                * Allocate the node data structures on the node first.
-                */
-               node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
-               node_data[node]->bdata = &plat_node_bdata[node];
-
-               hub_data[node] = (struct hub_data *)(node_data[node] + 1);
-
-               cpus_clear(hub_data[node]->h_cpus);
-
-               slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
-                                      sizeof(struct hub_data));
-       
-               bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn,
-                                               slot_firstpfn, slot_lastpfn);
-               free_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
-                               (slot_lastpfn - slot_firstpfn) << PAGE_SHIFT);
-               reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
-                 ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size);
+       for (node = 0; node < MAX_COMPACT_NODES; node++) {
+               if (node < numnodes) {
+                       node_mem_init(node);
+                       continue;
+               }
+               __node_data[node] = &null_node;
        }
 }
 
index 1e5ce4c..1103e29 100644 (file)
@@ -122,10 +122,6 @@ void cpu_node_probe(void)
        printk("Discovered %d cpus on %d nodes\n", highest + 1, numnodes);
 }
 
-void __init prom_build_cpu_map(void)
-{
-}
-
 static void intr_clear_bits(nasid_t nasid, volatile hubreg_t *pend,
        int base_level)
 {
@@ -158,9 +154,6 @@ void __init prom_prepare_cpus(unsigned int max_cpus)
        for (cnode = 0; cnode < numnodes; cnode++)
                intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
 
-       /* Master has already done per_cpu_init() */
-       install_ipi();
-
        replicate_kernel_text(numnodes);
 
        /*
index cc0419a..9d384d1 100644 (file)
@@ -112,9 +112,7 @@ again:
        if (cpu == 0)
                do_timer(regs);
 
-#ifdef CONFIG_SMP
        update_process_times(user_mode(regs));
-#endif /* CONFIG_SMP */
 
        /*
         * If we have an externally synchronized Linux clock, then update
index a8c7a77..7f771bf 100644 (file)
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <asm/bootinfo.h>
+#include <asm/io.h>
 #include <asm/mipsregs.h>
 #include <asm/ptrace.h>
 #include <asm/page.h>
 #include <asm/ip32/crime.h>
 #include <asm/ip32/mace.h>
 
-void *sgi_crime;
+struct sgi_crime *crime;
 struct sgi_mace *mace;
 
 void __init crime_init(void)
@@ -24,13 +25,12 @@ void __init crime_init(void)
        unsigned int id, rev;
        const int field = 2 * sizeof(unsigned long);
        
-       sgi_crime = ioremap(CRIME_BASE, 1);
+       crime = ioremap(CRIME_BASE, sizeof(struct sgi_crime));
        mace = ioremap(MACE_BASE, sizeof(struct sgi_mace));
 
-       id = crime_read(CRIME_ID);
+       id = crime->id;
        rev = id & CRIME_ID_REV;
        id = (id & CRIME_ID_IDBITS) >> 4;
-
        printk (KERN_INFO "CRIME id %1x rev %d at 0x%0*lx\n",
                id, rev, field, (unsigned long) CRIME_BASE);
 }
@@ -41,19 +41,18 @@ crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
        unsigned long stat, addr;
        int fatal = 0;
 
-       stat = crime_read(CRIME_MEM_ERROR_STAT) & CRIME_MEM_ERROR_STAT_MASK;
-       addr = crime_read(CRIME_MEM_ERROR_ADDR) & CRIME_MEM_ERROR_ADDR_MASK;
+       stat = crime->mem_error_stat & CRIME_MEM_ERROR_STAT_MASK;
+       addr = crime->mem_error_addr & CRIME_MEM_ERROR_ADDR_MASK;
 
        printk("CRIME memory error at 0x%08lx ST 0x%08lx<", addr, stat);
 
        if (stat & CRIME_MEM_ERROR_INV)
                printk("INV,");
        if (stat & CRIME_MEM_ERROR_ECC) {
-               unsigned long ecc_syn = crime_read(CRIME_MEM_ERROR_ECC_SYN) &
-                                       CRIME_MEM_ERROR_ECC_SYN_MASK;
-               unsigned long ecc_gen = crime_read(CRIME_MEM_ERROR_ECC_CHK) &
-                                       CRIME_MEM_ERROR_ECC_CHK_MASK;
-
+               unsigned long ecc_syn =
+                       crime->mem_ecc_syn & CRIME_MEM_ERROR_ECC_SYN_MASK;
+               unsigned long ecc_gen =
+                       crime->mem_ecc_chk & CRIME_MEM_ERROR_ECC_CHK_MASK;
                printk("ECC,SYN=0x%08lx,GEN=0x%08lx,", ecc_syn, ecc_gen);
        }
        if (stat & CRIME_MEM_ERROR_MULTIPLE) {
@@ -77,7 +76,7 @@ crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
        if (stat & CRIME_MEM_ERROR_MACE_ACCESS)
                printk("MACE,MACEID=0x%02lx,", stat & CRIME_MEM_ERROR_MACE_ID);
 
-       crime_write(0, CRIME_MEM_ERROR_STAT);
+       crime->mem_error_stat = 0;
 
        if (fatal) {
                printk("FATAL>\n");
@@ -91,15 +90,12 @@ crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
 irqreturn_t
 crime_cpuerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
 {
-       unsigned long stat = crime_read(CRIME_CPU_ERROR_STAT) &
-                            CRIME_CPU_ERROR_MASK;
-       uint64_t addr = crime_read(CRIME_CPU_ERROR_ADDR) &
-                       CRIME_CPU_ERROR_ADDR_MASK;
-       addr <<= 2;
+       unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK;
+       unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK;
 
+       addr <<= 2;
        printk ("CRIME CPU error at 0x%09lx status 0x%08lx\n", addr, stat);
-
-       crime_write(0, CRIME_CPU_ERROR_STAT);
+       crime->cpu_error_stat = 0;
 
        return IRQ_HANDLED;
 }
index ac65798..6340468 100644 (file)
@@ -41,7 +41,7 @@ static void ip32_machine_power_off(void) __attribute__((noreturn));
 
 static void ip32_machine_restart(char *cmd)
 {
-       crime_write(CRIME_CONTROL_HARD_RESET, CRIME_CONTROL);
+       crime->control = CRIME_CONTROL_HARD_RESET;
        while (1);
 }
 
@@ -83,9 +83,9 @@ static void power_timeout(unsigned long data)
 
 static void blink_timeout(unsigned long data)
 {
-       unsigned long led = mace_perif_ctrl_read(misc) ^ MACEISA_LED_RED;
-       mace_perif_ctrl_write(led, misc);
-       mod_timer(&blink_timer, jiffies+data);
+       unsigned long led = mace->perif.ctrl.misc ^ MACEISA_LED_RED;
+       mace->perif.ctrl.misc = led;
+       mod_timer(&blink_timer, jiffies + data);
 }
 
 static void debounce(unsigned long data)
@@ -165,8 +165,8 @@ static int panic_event(struct notifier_block *this, unsigned long event,
        has_paniced = 1;
 
        /* turn off the green LED */
-       led = mace_perif_ctrl_read(misc) | MACEISA_LED_GREEN;
-       mace_perif_ctrl_write(led, misc);
+       led = mace->perif.ctrl.misc | MACEISA_LED_GREEN;
+       mace->perif.ctrl.misc = led;
 
        blink_timer.data = PANIC_FREQ;
        blink_timeout(PANIC_FREQ);
@@ -181,10 +181,10 @@ static struct notifier_block panic_block = {
 static __init int ip32_reboot_setup(void)
 {
        /* turn on the green led only */
-       unsigned long led = mace_perif_ctrl_read(misc);
+       unsigned long led = mace->perif.ctrl.misc;
        led |= MACEISA_LED_RED;
        led &= ~MACEISA_LED_GREEN;
-       mace_perif_ctrl_write(led, misc);
+       mace->perif.ctrl.misc = led;
 
        _machine_restart = ip32_machine_restart;
        _machine_halt = ip32_machine_halt;
index 51cad2d..5fccded 100644 (file)
@@ -80,8 +80,8 @@ void __init ip32_time_init(void)
 {
        printk(KERN_INFO "Calibrating system timer... ");
        write_c0_count(0);
-       crime_write(0, CRIME_TIMER);
-       while (crime_read(CRIME_TIMER) < CRIME_MASTER_FREQ * WAIT_MS / 1000) ;
+       crime->timer = 0;
+       while (crime->timer < CRIME_MASTER_FREQ * WAIT_MS / 1000) ;
        mips_hpt_frequency = read_c0_count() * 1000 / WAIT_MS;
        printk("%d MHz CPU detected\n", mips_hpt_frequency * 2 / 1000000);
 }
@@ -114,7 +114,7 @@ static int __init ip32_setup(void)
                o2_serial[0].type       = PORT_16550A;
                o2_serial[0].line       = 0;
                o2_serial[0].irq        = MACEISA_SERIAL1_IRQ;
-               o2_serial[0].flags      = STD_COM_FLAGS | UPF_RESOURCES;
+               o2_serial[0].flags      = STD_COM_FLAGS;
                o2_serial[0].uartclk    = BASE_BAUD * 16;
                o2_serial[0].iotype     = UPIO_MEM;
                o2_serial[0].membase    = (char *)&mace->isa.serial1;
@@ -125,7 +125,7 @@ static int __init ip32_setup(void)
                o2_serial[1].type       = PORT_16550A;
                o2_serial[1].line       = 1;
                o2_serial[1].irq        = MACEISA_SERIAL2_IRQ;
-               o2_serial[1].flags      = STD_COM_FLAGS | UPF_RESOURCES;
+               o2_serial[1].flags      = STD_COM_FLAGS;
                o2_serial[1].uartclk    = BASE_BAUD * 16;
                o2_serial[1].iotype     = UPIO_MEM;
                o2_serial[1].membase    = (char *)&mace->isa.serial2;
index 3dd85d5..d6d0364 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/linkage.h>
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/bootmem.h>
@@ -55,36 +56,45 @@ int cfe_cons_handle;
 
 #ifdef CONFIG_BLK_DEV_INITRD
 extern unsigned long initrd_start, initrd_end;
-extern void * __rd_start, * __rd_end;
-#endif
-
-#ifdef CONFIG_SMP
-static int reboot_smp = 0;
 #endif
 
 #ifdef CONFIG_KGDB
 extern int kgdb_port;
 #endif
 
-static void cfe_linux_exit(void)
+static void ATTRIB_NORET cfe_linux_exit(void *arg)
 {
-#ifdef CONFIG_SMP
+       int warm = *(int *)arg;
+
        if (smp_processor_id()) {
-               if (reboot_smp) {
-                       /* Don't repeat the process from another CPU */
-                       for (;;);
-               } else {
+               static int reboot_smp;
+
+               /* Don't repeat the process from another CPU */
+               if (!reboot_smp) {
                        /* Get CPU 0 to do the cfe_exit */
                        reboot_smp = 1;
-                       smp_call_function((void *)_machine_restart, NULL, 1, 0);
-                       for (;;);
+                       smp_call_function(cfe_linux_exit, arg, 1, 0);
                }
+       } else {
+               printk("Passing control back to CFE...\n");
+               cfe_exit(warm, 0);
+               printk("cfe_exit returned??\n");
        }
-#endif
-       printk("passing control back to CFE\n");
-       cfe_exit(1, 0);
-       printk("cfe_exit returned??\n");
-       while(1);
+       while (1);
+}
+
+static void ATTRIB_NORET cfe_linux_restart(char *command)
+{
+       static const int zero;
+
+       cfe_linux_exit((void *)&zero);
+}
+
+static void ATTRIB_NORET cfe_linux_halt(void)
+{
+       static const int one = 1;
+
+       cfe_linux_exit((void *)&one);
 }
 
 static __init void prom_meminit(void)
@@ -97,17 +107,6 @@ static __init void prom_meminit(void)
        unsigned long initrd_pstart;
        unsigned long initrd_pend;
 
-#ifdef CONFIG_EMBEDDED_RAMDISK
-       /* If we're using an embedded ramdisk, then __rd_start and __rd_end
-          are defined by the linker to be on either side of the ramdisk
-          area.  Otherwise, initrd_start should be defined by kernel command
-          line arguments */
-       if (initrd_start == 0) {
-               initrd_start = (unsigned long)&__rd_start;
-               initrd_end = (unsigned long)&__rd_end;
-       }
-#endif
-
        initrd_pstart = CPHYSADDR(initrd_start);
        initrd_pend = CPHYSADDR(initrd_end);
        if (initrd_start &&
@@ -247,9 +246,9 @@ void __init prom_init(void)
        char *arg;
 #endif
 
-       _machine_restart   = (void (*)(char *))cfe_linux_exit;
-       _machine_halt      = cfe_linux_exit;
-       _machine_power_off = cfe_linux_exit;
+       _machine_restart   = cfe_linux_restart;
+       _machine_halt      = cfe_linux_halt;
+       _machine_power_off = cfe_linux_halt;
 
        /*
         * Check if a loader was used; if NOT, the 4 arguments are
index fada704..7339219 100644 (file)
  * Use CFE to find out how many CPUs are available, setting up
  * phys_cpu_present_map and the logical/physical mappings.
  * XXXKW will the boot CPU ever not be physical 0?
+ *
+ * Common setup before any secondaries are started
  */
-void __init prom_build_cpu_map(void)
+void __init prom_prepare_cpus(unsigned int max_cpus)
 {
        int i, num;
 
@@ -48,13 +50,6 @@ void __init prom_build_cpu_map(void)
        printk("Detected %i available secondary CPU(s)\n", num);
 }
 
-/*
- * Common setup before any secondaries are started
- */
-void prom_prepare_cpus(unsigned int max_cpus)
-{
-}
-
 /*
  * Setup the PC, SP, and GP of a secondary processor and start it
  * running!
index 426fb30..de62ab0 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/bootmem.h>
 #include <linux/smp.h>
+#include <linux/initrd.h>
 
 #include <asm/bootinfo.h>
 #include <asm/reboot.h>
 
-#ifdef CONFIG_EMBEDDED_RAMDISK
-/* These are symbols defined by the ramdisk linker script */
-extern unsigned char __rd_start;
-extern unsigned char __rd_end;
-#endif
-
 #define MAX_RAM_SIZE ((CONFIG_SIBYTE_STANDALONE_RAM_SIZE * 1024 * 1024) - 1)
 
 static __init void prom_meminit(void)
@@ -41,17 +36,6 @@ static __init void prom_meminit(void)
        unsigned long initrd_pstart;
        unsigned long initrd_pend;
 
-#ifdef CONFIG_EMBEDDED_RAMDISK
-       /* If we're using an embedded ramdisk, then __rd_start and __rd_end
-          are defined by the linker to be on either side of the ramdisk
-          area.  Otherwise, initrd_start should be defined by kernel command
-          line arguments */
-       if (initrd_start == 0) {
-               initrd_start = (unsigned long)&__rd_start;
-               initrd_end = (unsigned long)&__rd_end;
-       }
-#endif
-
        initrd_pstart = __pa(initrd_start);
        initrd_pend = __pa(initrd_end);
        if (initrd_start &&
index 638da09..9e7336c 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
+ * Copyright (C) 2004 by 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
@@ -26,6 +27,8 @@
 #include <linux/bootmem.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/initrd.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -34,7 +37,6 @@
 #include <asm/reboot.h>
 #include <asm/time.h>
 #include <asm/traps.h>
-#include <asm/pci_channel.h>
 #include <asm/sibyte/sb1250.h>
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_genbus.h>
index caa44d1..afb6602 100644 (file)
@@ -173,13 +173,12 @@ void __init init_pciasic(void)
  * driver compatibility reasons interrupts 0 - 15 to be the i8295
  * interrupts even if the hardware uses a different interrupt numbering.
  */
-void __init init_IRQ (void)
+void __init arch_init_irq(void)
 {
        int i;
 
        set_except_vector(0, sni_rm200_pci_handle_int);
 
-       init_generic_irq();
        init_i8259_irqs();                      /* Integrated i8259  */
        init_pciasic();
 
index d2fa8b1..8f67cee 100644 (file)
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004 by Ralf Baechle
+ * Copyright (C) 1996, 97, 98, 2000, 03, 04 Ralf Baechle (ralf@linux-mips.org)
  */
 #include <linux/config.h>
 #include <linux/eisa.h>
@@ -27,7 +27,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mc146818-time.h>
-#include <asm/pci_channel.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/reboot.h>
index 573c753..8fa126b 100644 (file)
@@ -8,4 +8,5 @@
 
 obj-y  += tx4927_prom.o tx4927_setup.o tx4927_irq.o tx4927_irq_handler.o
 
+obj-$(CONFIG_TOSHIBA_FPCIB0)      += smsc_fdc37m81x.o
 obj-$(CONFIG_KGDB)                 += tx4927_dbgio.o
index 73d188f..16bcbdc 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/irq.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -92,15 +92,6 @@ void __init tx4927_time_init(void)
        }
 #endif
 
-#ifdef CONFIG_KGDB
-       {
-               printk("Calling breakpoint() -- start remote kgdb\n");
-               set_debug_traps();
-               breakpoint();
-               printk("Calling breakpoint() -- done\n");
-       }
-#endif
-
        return;
 }
 
index 3519020..e4d095d 100644 (file)
@@ -6,6 +6,9 @@
  *
  * Copyright 2001-2002 MontaVista Software Inc.
  *
+ * 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
@@ -86,3 +89,9 @@ const char *get_system_type(void)
 {
        return "Toshiba RBTX4927/RBTX4937";
 }
+
+char * __init prom_getcmdline(void)
+{
+        return &(arcs_cmdline[0]);
+}
+
index 77698da..b2385c1 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright 2001-2002 MontaVista Software Inc.
  *
- * Copyright (C) 1996, 1997, 2001  Ralf Baechle
+ * Copyright (C) 1996, 97, 2001, 04  Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 2000 RidgeRun, Inc.
  * Author: RidgeRun, Inc.
  *   glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
  * Copyright 2002 MontaVista Software Inc.
  * Author: Michael Pruznick, michael_pruznick@mvista.com
  *
- * Copyright (C) 2000-2001 Toshiba Corporation 
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * 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
 #include <linux/bootmem.h>
 #include <linux/blkdev.h>
 #ifdef CONFIG_RTC_DS1742
-#include <asm/rtc_ds1742.h>
+#include <linux/ds1742rtc.h>
 #endif
 #ifdef CONFIG_TOSHIBA_FPCIB0
-#include <asm/smsc_fdc37m81x.h>
+#include <asm/tx4927/smsc_fdc37m81x.h>
 #endif
 #include <asm/tx4927/toshiba_rbtx4927.h>
 #ifdef CONFIG_PCI
 #include <asm/tx4927/tx4927_pci.h>
-#include <asm/pci_channel.h>
 #endif
 #ifdef CONFIG_BLK_DEV_IDEPCI
 #include <linux/hdreg.h>
@@ -146,49 +148,15 @@ static int tx4927_pcic_trdyto = 0;        /* default: disabled */
 unsigned long tx4927_ce_base[8];
 void tx4927_pci_setup(void);
 void tx4927_reset_pci_pcic(void);
-#ifdef  TX4927_SUPPORT_PCI_66
-void tx4927_pci66_setup(void);
-extern int tx4927_pci66_check(void);
-#endif
 int tx4927_pci66 = 0;          /* 0:auto */
 #endif
 
 char *toshiba_name = "";
 
 #ifdef CONFIG_PCI
-void tx4927_dump_pcic_settings(void)
-{
-       printk("%s pcic settings:",toshiba_name);
-       {
-               int i;
-               unsigned long *preg = (unsigned long *) tx4927_pcicptr;
-               for (i = 0; i < sizeof(struct tx4927_pcic_reg); i += 4) {
-                       if (i % 32 == 0)
-                               printk("\n%04x:", i);
-                       if (preg == &tx4927_pcicptr->g2pintack
-                           || preg == &tx4927_pcicptr->g2pspc
-#ifdef CONFIG_TX4927BUG_WORKAROUND
-                           || preg == &tx4927_pcicptr->g2pcfgadrs
-                           || preg == &tx4927_pcicptr->g2pcfgdata
-#endif
-                           ) {
-                               printk(" XXXXXXXX");
-                               preg++;
-                               continue;
-                       }
-                       printk(" %08lx", *preg++);
-                       if (preg == &tx4927_pcicptr->g2pcfgadrs)
-                               break;
-               }
-               printk("\n");
-       }
-}
-
 static void tx4927_pcierr_interrupt(int irq, void *dev_id,
                                    struct pt_regs *regs)
 {
-       extern void tx4927_dump_pcic_settings(void);
-
 #ifdef CONFIG_BLK_DEV_IDEPCI
        /* ignore MasterAbort for ide probing... */
        if (irq == TX4927_IRQ_IRC_PCIERR &&
@@ -203,6 +171,7 @@ static void tx4927_pcierr_interrupt(int irq, void *dev_id,
        }
 #endif
        printk("PCI error interrupt (irq 0x%x).\n", irq);
+
        printk("pcistat:%04x, g2pstatus:%08lx, pcicstatus:%08lx\n",
               (unsigned short) (tx4927_pcicptr->pcistatus >> 16),
               tx4927_pcicptr->g2pstatus, tx4927_pcicptr->pcicstatus);
@@ -211,23 +180,10 @@ static void tx4927_pcierr_interrupt(int irq, void *dev_id,
               (unsigned long) (tx4927_ccfgptr->tear >> 32),
               (unsigned long) tx4927_ccfgptr->tear);
        show_regs(regs);
-       //tx4927_dump_pcic_settings();
-       panic("PCI error at PC:%08lx.", regs->cp0_epc);
 }
 
-static struct irqaction pcic_action = {
-       tx4927_pcierr_interrupt, 0, 0, "PCI-C", NULL, NULL
-};
-
-static struct irqaction pcierr_action = {
-       tx4927_pcierr_interrupt, 0, 0, "PCI-ERR", NULL, NULL
-};
-
-
 void __init toshiba_rbtx4927_pci_irq_init(void)
 {
-       setup_irq(TX4927_IRQ_IRC_PCIC, &pcic_action);
-       setup_irq(TX4927_IRQ_IRC_PCIERR, &pcierr_action);
        return;
 }
 
@@ -245,91 +201,26 @@ void tx4927_reset_pci_pcic(void)
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_PCI
-#ifdef  TX4927_SUPPORT_PCI_66
-void tx4927_pci66_setup(void)
-{
-       int pciclk, pciclkin = 1;
-
-       TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_PCI66,
-                                      "-\n");
-
-       if (tx4927_ccfgptr->ccfg & TX4927_CCFG_PCI66)
-               return;
-
-       tx4927_reset_pci_pcic();
-
-       /* Assert M66EN */
-       tx4927_ccfgptr->ccfg |= TX4927_CCFG_PCI66;
-       /* set PCICLK 66MHz */
-       if (tx4927_ccfgptr->pcfg & TX4927_PCFG_PCICLKEN_ALL) {
-               unsigned int pcidivmode = 0;
-               pcidivmode =
-                   (unsigned long) tx4927_ccfgptr->
-                   ccfg & TX4927_CCFG_PCIDIVMODE_MASK;
-               if (tx4927_cpu_clock >= 170000000) {
-                       /* CPU 200MHz */
-                       pcidivmode = TX4927_CCFG_PCIDIVMODE_3;
-                       pciclk = tx4927_cpu_clock / 3;
-               } else {
-                       /* CPU 166MHz */
-                       pcidivmode = TX4927_CCFG_PCIDIVMODE_2_5;
-                       pciclk = tx4927_cpu_clock * 2 / 5;
-               }
-               tx4927_ccfgptr->ccfg =
-                   (tx4927_ccfgptr->ccfg & ~TX4927_CCFG_PCIDIVMODE_MASK)
-                   | pcidivmode;
-               TOSHIBA_RBTX4927_SETUP_DPRINTK
-                   (TOSHIBA_RBTX4927_SETUP_PCI66,
-                    ":PCICLK: ccfg:0x%08lx\n",
-                    (unsigned long) tx4927_ccfgptr->ccfg);
-       } else {
-               int pciclk_setting = *tx4927_pci_clk_ptr;
-               pciclkin = 0;
-               pciclk = 66666666;
-               pciclk_setting &= ~TX4927_PCI_CLK_MASK;
-               pciclk_setting |= TX4927_PCI_CLK_66;
-               *tx4927_pci_clk_ptr = pciclk_setting;
-               TOSHIBA_RBTX4927_SETUP_DPRINTK
-                   (TOSHIBA_RBTX4927_SETUP_PCI66,
-                    "PCICLK: pci_clk:%02x\n", *tx4927_pci_clk_ptr);
-       }
-
-       udelay(10000);
-
-       /* clear PCIC reset */
-       tx4927_ccfgptr->clkctr &= ~TX4927_CLKCTR_PCIRST;
-       /* clear PCI reset */
-       *tx4927_pcireset_ptr = 0;
-
-       TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_PCI66,
-                                      "+\n");
-       return;
-}
-#endif                         /* TX4927_SUPPORT_PCI_66 */
-
 void print_pci_status(void)
 {
        printk("PCI STATUS %lx\n", tx4927_pcicptr->pcistatus);
        printk("PCIC STATUS %lx\n", tx4927_pcicptr->pcicstatus);
 }
 
+extern struct pci_controller tx4927_controller;
+
 static struct pci_dev *fake_pci_dev(struct pci_controller *hose,
                                    int top_bus, int busnr, int devfn)
 {
        static struct pci_dev dev;
        static struct pci_bus bus;
 
-       dev.bus = &bus;
-       dev.sysdata = hose;
+       dev.sysdata = (void *)hose;
        dev.devfn = devfn;
        bus.number = busnr;
        bus.ops = hose->pci_ops;
-
-       if (busnr != top_bus)
-               /* Fake a parent bus structure. */
-               bus.parent = &bus;
-       else
-               bus.parent = NULL;
+       bus.parent = NULL;
+       dev.bus = &bus;
 
        return &dev;
 }
@@ -350,15 +241,19 @@ EARLY_PCI_OP(write, byte, u8)
 EARLY_PCI_OP(write, word, u16)
 EARLY_PCI_OP(write, dword, u32)
 
-static int __init tx4927_pcibios_init(int busno, struct pci_controller *hose)
+static int __init tx4927_pcibios_init(void)
 {
        unsigned int id;
        u32 pci_devfn;
+       int devfn_start = 0;
+       int devfn_stop = 0xff;
+       int busno = 0; /* One bus on the Toshiba */
+       struct pci_controller *hose = &tx4927_controller;
 
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_PCIBIOS,
                                       "-\n");
 
-       for (pci_devfn = 0x0; pci_devfn < 0xff; pci_devfn++) {
+       for (pci_devfn = devfn_start; pci_devfn < devfn_stop; pci_devfn++) {
                early_read_config_dword(hose, busno, busno, pci_devfn,
                                        PCI_VENDOR_ID, &id);
 
@@ -581,12 +476,15 @@ static int __init tx4927_pcibios_init(int busno, struct pci_controller *hose)
 
        }
 
+       register_pci_controller(&tx4927_controller);
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_PCIBIOS,
                                       "+\n");
 
-       return busno;
+       return 0;
 }
 
+arch_initcall(tx4927_pcibios_init);
+
 extern struct resource pci_io_resource;
 extern struct resource pci_mem_resource;
 
@@ -597,11 +495,6 @@ void tx4927_pci_setup(void)
 
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_PCI2, "-\n");
 
-#ifndef  TX4927_SUPPORT_PCI_66
-       if (tx4927_ccfgptr->ccfg & TX4927_CCFG_PCI66)
-               printk("PCI 66 current unsupported\n");
-#endif
-
        mips_memory_upper = tx4927_get_mem_size() << 20;
        mips_memory_upper += KSEG0;
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_PCI2,
@@ -736,19 +629,6 @@ void tx4927_pci_setup(void)
        /* PCI->GB mappings (I/O 256B) */
        tx4927_pcicptr->p2giopbase = 0; /* 256B */
 
-
-#ifdef TX4927_SUPPORT_COMMAND_IO
-       tx4927_pcicptr->p2giogbase = 0 | TX4927_PCIC_P2GIOGBASE_TIOEN |
-#ifdef __BIG_ENDIAN
-           TX4927_PCIC_P2GIOGBASE_TECHG
-#else
-           TX4927_PCIC_P2GIOGBASE_TBSDIS
-#endif
-           ;
-#else
-       tx4927_pcicptr->p2giogbase = 0;
-#endif
-
        /* PCI->GB mappings (MEM 512MB) M0 gets all of memory */
        tx4927_pcicptr->p2gm0plbase = 0;
        tx4927_pcicptr->p2gm0pubase = 0;
@@ -791,8 +671,6 @@ void tx4927_pci_setup(void)
        if (tx4927_pcic_trdyto >= 0) {
                tx4927_pcicptr->g2ptocnt &= ~0xff;
                tx4927_pcicptr->g2ptocnt |= (tx4927_pcic_trdyto & 0xff);
-               //printk("%s PCIC -- TRDYTO:%02lx\n",toshiba_name,
-               //      tx4927_pcicptr->g2ptocnt & 0xff);
        }
 
        /* Clear All Local Bus Status */
@@ -825,17 +703,10 @@ void tx4927_pci_setup(void)
 
        tx4927_pcicptr->pcistatus = PCI_COMMAND_MASTER |
            PCI_COMMAND_MEMORY |
-#ifdef TX4927_SUPPORT_COMMAND_IO
-           PCI_COMMAND_IO |
-#endif
            PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
 
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_PCI2,
                                       ":pci setup complete:\n");
-       //tx4927_dump_pcic_settings();
-
-       tx4927_pcibios_init(0, &tx4927_controller);
-
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_PCI2, "+\n");
 }
 
@@ -883,6 +754,7 @@ void toshiba_rbtx4927_power_off(void)
 void __init toshiba_rbtx4927_setup(void)
 {
        vu32 cp0_config;
+       char *argptr;
 
        printk("CPU is %s\n", toshiba_name);
 
@@ -923,21 +795,16 @@ void __init toshiba_rbtx4927_setup(void)
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_SETUP,
                                       "+\n");
 
-
-
-       mips_io_port_base = KSEG1 + TBTX4927_ISA_IO_OFFSET;
+       set_io_port_base(KSEG1 + TBTX4927_ISA_IO_OFFSET);
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_SETUP,
                                       ":mips_io_port_base=0x%08lx\n",
                                       mips_io_port_base);
 
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_SETUP,
                                       ":Resource\n");
-       ioport_resource.start = 0;
        ioport_resource.end = 0xffffffff;
-       iomem_resource.start = 0;
        iomem_resource.end = 0xffffffff;
 
-
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_SETUP,
                                       ":ResetRoutines\n");
        _machine_restart = toshiba_rbtx4927_restart;
@@ -1000,25 +867,11 @@ void __init toshiba_rbtx4927_setup(void)
                tx4927_sdramcptr->tr |= 0x02000000;     /* RCD:3tck */
 #endif
 
-#ifdef  TX4927_SUPPORT_PCI_66
-       tx4927_pci66_setup();
-#endif
-
        tx4927_pci_setup();
-#endif
-
-
-       {
-               u32 id = 0;
-               early_read_config_dword(&tx4927_controller, 0, 0, 0x90,
-                                       PCI_VENDOR_ID, &id);
-               if (id == 0x94601055) {
-                       tx4927_using_backplane = 1;
-                       printk("backplane board IS installed\n");
-               } else {
-                       printk("backplane board NOT installed\n");
-               }
-       }
+       if (tx4927_using_backplane == 1)
+               printk("backplane board IS installed\n");
+       else
+               printk("No Backplane \n");
 
        /* this is on ISA bus behind PCI bus, so need PCI up first */
 #ifdef CONFIG_TOSHIBA_FPCIB0
@@ -1065,11 +918,41 @@ void __init toshiba_rbtx4927_setup(void)
        }
 #endif
 
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_SERIAL_TXX9_CONSOLE
+        argptr = prom_getcmdline();
+        if (strstr(argptr, "console=") == NULL) {
+                strcat(argptr, " console=ttyS0,38400");
+        }
+#endif
+
+#ifdef CONFIG_ROOT_NFS
+        argptr = prom_getcmdline();
+        if (strstr(argptr, "root=") == NULL) {
+                strcat(argptr, " root=/dev/nfs rw");
+        }
+#endif
+
+
+#ifdef CONFIG_IP_PNP
+        argptr = prom_getcmdline();
+        if (strstr(argptr, "ip=") == NULL) {
+                strcat(argptr, " ip=any");
+        }
+#endif
+
 
        TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_SETUP,
-                                      "+\n");
+                              "+\n");
 }
 
+#ifdef CONFIG_RTC_DS1742
+extern unsigned long rtc_ds1742_get_time(void);
+extern int rtc_ds1742_set_time(unsigned long);
+extern void rtc_ds1742_wait(void);
+#endif
+
 void __init
 toshiba_rbtx4927_time_init(void)
 {
index 0800eb3..d7c80ed 100644 (file)
@@ -43,8 +43,11 @@ int hpux_execve(struct pt_regs *regs)
        error = do_execve(filename, (char **) regs->gr[25],
                (char **)regs->gr[24], regs);
 
-       if (error == 0)
+       if (error == 0) {
+               task_lock(current);
                current->ptrace &= ~PT_DTRACE;
+               task_unlock(current);
+       }
        putname(filename);
 
 out:
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
index dadcf13..1ac65cf 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/string.h>
 EXPORT_SYMBOL(memchr);
 EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(memset);
@@ -65,13 +64,20 @@ EXPORT_SYMBOL(__cmpxchg_u64);
 #endif
 
 #include <asm/uaccess.h>
-EXPORT_SYMBOL(lcopy_to_user);
-EXPORT_SYMBOL(lcopy_from_user);
-EXPORT_SYMBOL(lcopy_in_user);
 EXPORT_SYMBOL(lstrncpy_from_user);
 EXPORT_SYMBOL(lclear_user);
 EXPORT_SYMBOL(lstrnlen_user);
 
+/* Global fixups */
+extern void fixup_get_user_skip_1(void);
+extern void fixup_get_user_skip_2(void);
+extern void fixup_put_user_skip_1(void);
+extern void fixup_put_user_skip_2(void);
+EXPORT_SYMBOL(fixup_get_user_skip_1);
+EXPORT_SYMBOL(fixup_get_user_skip_2);
+EXPORT_SYMBOL(fixup_put_user_skip_1);
+EXPORT_SYMBOL(fixup_put_user_skip_2);
+
 #ifndef __LP64__
 /* Needed so insmod can set dp value */
 extern int $global$;
index 8072e38..01f676d 100644 (file)
@@ -71,6 +71,19 @@ void pdc_outc(unsigned char c)
        pdc_iodc_outc(c);
 }
 
+void pdc_printf(const char *fmt, ...)
+{
+       va_list args;
+       char buf[1024];
+       int i, len;
+
+       va_start(args, fmt);
+       len = vscnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+
+       for (i = 0; i < len; i++)
+               pdc_iodc_outc(buf[i]);
+}
 
 int pdc_console_poll_key(struct console *co)
 {
index 884be87..87993ae 100644 (file)
@@ -1,18 +1,19 @@
 
 /*    low-level asm for "intrigue" (PA8500-8700 CPU perf counters)
- *
+ * 
  *    Copyright (C) 2001 Randolph Chung <tausq at parisc-linux.org>
- *
+ *    Copyright (C) 2001 Hewlett-Packard (Grant Grundler)
+ * 
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the 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
@@ -48,7 +49,7 @@ perf_intrigue_enable_perf_counters:
        .proc
        .callinfo  frame=0,NO_CALLS
        .entry
-       
+
        ldi     0x20,%r25                ; load up perfmon bit
        mfctl   ccr,%r26                 ; get coprocessor register
        or      %r25,%r26,%r26             ; set bit
@@ -87,35 +88,35 @@ perf_intrigue_disable_perf_counters:
        .exit
        .procend
 
-;************************************************************************
-;*                                                                                                                                             *
-;* Name: perf_rdr_shift_in_W                                                                                           *
-;*                                                                                                                                             *
-;* Description:                                                                                                                        *
-;*     This routine shifts data in from the RDR in arg0 and returns            *
-;*     the result in ret0.  If the RDR is <= 64 bits in length, it                     *
-;*     is shifted shifted backup immediately.  This is to compensate           *
-;*     for RDR10 which has bits that preclude PDC stack operations                     *
-;*     when they are in the wrong state.                                                                       *
-;*                                                                                                                                             *
-;* Arguments:                                                                                                                  *
-;*     arg0 : rdr to be read                                                                                           *
-;*     arg1 : bit length of rdr                                                                                        *
-;*                                                                                                                                             *
-;* Returns:                                                                                                                            *
-;*     ret0 = next 64 bits of rdr data from staging register                           *
-;*                                                                                                                                             *
-;* Register usage:                                                                                                             *
-;*     arg0 : rdr to be read                                                                                           *
-;*     arg1 : bit length of rdr                                                                                        *
-;*     %r24  - original DR2 value                                                                                      *
-;*     %r1   - scratch                                                                                                         *
-;*  %r29  - scratch                                                                                                            *
-;*                                                                                                                                             *
-;* Returns:                                                                                                                            *
-;*     ret0 = RDR data (right justified)                                                                       *
-;*                                                                                                                                             *
-;************************************************************************
+;***********************************************************************
+;*
+;* Name: perf_rdr_shift_in_W
+;*
+;* Description:
+;*     This routine shifts data in from the RDR in arg0 and returns
+;*     the result in ret0.  If the RDR is <= 64 bits in length, it
+;*     is shifted shifted backup immediately.  This is to compensate
+;*     for RDR10 which has bits that preclude PDC stack operations
+;*     when they are in the wrong state.
+;*
+;* Arguments:
+;*     arg0 : rdr to be read
+;*     arg1 : bit length of rdr
+;*
+;* Returns:
+;*     ret0 = next 64 bits of rdr data from staging register
+;*
+;* Register usage:
+;*     arg0 : rdr to be read
+;*     arg1 : bit length of rdr
+;*     %r24  - original DR2 value
+;*     %r1   - scratch
+;*  %r29  - scratch
+;*
+;* Returns:
+;*     ret0 = RDR data (right justified)
+;*
+;***********************************************************************
 
        .export perf_rdr_shift_in_W,code
 perf_rdr_shift_in_W:
@@ -138,7 +139,7 @@ perf_rdr_shift_in_W:
        nop
        nop
        nop
-       nop     
+       nop
 
 ;
 ; Cacheline start (32-byte cacheline)
@@ -146,11 +147,11 @@ perf_rdr_shift_in_W:
        nop
        nop
        nop
-       extrd,u         arg1,63,6,%r1    ; setup shift amount based on bits to move 
+       extrd,u         arg1,63,6,%r1   ; setup shift amount by bits to move 
 
        mtsar           %r1
        shladd          arg0,2,%r0,%r1  ; %r1 = 4 * RDR number
-       blr             %r1,%r0             ; branch to 8-instruction sequence
+       blr             %r1,%r0         ; branch to 8-instruction sequence
        nop
 
 ;
@@ -160,19 +161,19 @@ perf_rdr_shift_in_W:
        ;
        ; RDR 0 sequence
        ;
-       SFDIAG          (0)             
+       SFDIAG          (0)
        ssm                 0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
-       MTDIAG_1        (1)                                     ; mtdiag %dr1, %r1 
+       MTDIAG_1        (1)                     ; mtdiag %dr1, %r1 
        STDIAG          (0)
        ssm                 0,0
        b,n         perf_rdr_shift_in_W_leave
-       
+
        ;
        ; RDR 1 sequence
        ;
-       sync                    
+       sync
        ssm                 0,0
        SFDIAG          (1)
        ssm                 0,0
@@ -180,11 +181,11 @@ perf_rdr_shift_in_W:
        ssm                 0,0
        b,n         perf_rdr_shift_in_W_leave
        nop
-       
+
        ;
        ; RDR 2 read sequence
        ;
-       SFDIAG          (2)             
+       SFDIAG          (2)
        ssm                 0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
@@ -192,7 +193,7 @@ perf_rdr_shift_in_W:
        STDIAG          (2)
        ssm                 0,0
        b,n         perf_rdr_shift_in_W_leave
-       
+
        ;
        ; RDR 3 read sequence
        ;
@@ -208,39 +209,39 @@ perf_rdr_shift_in_W:
        ;
        ; RDR 4 read sequence
        ;
-       sync                            
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (4)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ; 
        ; RDR 5 read sequence
        ;
-       sync    
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (5)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 6 read sequence
        ;
-       sync    
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (6)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 7 read sequence
        ;
@@ -281,26 +282,26 @@ perf_rdr_shift_in_W:
        ; RDR 10 read sequence
        ;
        SFDIAG          (10)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (10)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_W_leave
-       
+
        ;
        ; RDR 11 read sequence
        ;
        SFDIAG          (11)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (11)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_W_leave
-       
+
        ;
        ; RDR 12 read sequence
        ;
@@ -317,77 +318,77 @@ perf_rdr_shift_in_W:
        ; RDR 13 read sequence
        ;
        sync
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (13)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 14 read sequence
        ;
-       SFDIAG          (14)    
-       ssm                     0,0
+       SFDIAG          (14)
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (14)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_W_leave
-       
+
        ;
        ; RDR 15 read sequence
        ;
-       sync                            ; RDR 15 read sequence
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (15)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_W_leave
        nop
-       
+
        ;
        ; RDR 16 read sequence
        ;
-       sync                            ; RDR 16 read sequence
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (16)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 17 read sequence
        ;
-       SFDIAG          (17)    
-       ssm                     0,0
+       SFDIAG          (17)
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (17)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_W_leave
-       
+
        ;
        ; RDR 18 read sequence
        ;
-       SFDIAG          (18)    
-       ssm                     0,0
+       SFDIAG          (18)
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (18)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_W_leave
-       
-;
-; RDR 19 read sequence
-;
+
+       ;
+       ; RDR 19 read sequence
+       ;
        b,n         perf_rdr_shift_in_W_leave
        nop
        nop
@@ -401,144 +402,144 @@ perf_rdr_shift_in_W:
        ; RDR 20 read sequence
        ;
        sync
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (20)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 21 read sequence
        ;
        sync
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (21)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 22 read sequence
        ;
        sync
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (22)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 23 read sequence
        ;
-       sync            
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (23)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 24 read sequence
        ;
-       sync    
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (24)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 25 read sequence
        ;
        sync
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (25)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 26 read sequence
        ;
-       SFDIAG          (26)            
-       ssm                     0,0
+       SFDIAG          (26)
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (26)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_W_leave
-       
+
        ;
        ; RDR 27 read sequence
        ;
        SFDIAG          (27)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (27)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_W_leave
-       
+
        ;
        ; RDR 28 read sequence
        ;
-       sync                            
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (28)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 29 read sequence
        ;
-       sync            
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (29)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_W_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        ;
        ; RDR 30 read sequence
        ;
        SFDIAG          (30)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (30)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_W_leave
-       
+
        ;
        ; RDR 31 read sequence
        ;
-       sync            
-       ssm                     0,0
+       sync
+       ssm             0,0
        SFDIAG          (31)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        ;
@@ -552,28 +553,28 @@ perf_rdr_shift_in_W_leave:
        .procend
 
 
-;************************************************************************
-;*                                                                                                                                             *
-;* Name: perf_rdr_shift_out_W                                                                                          *
-;*                                                                                                                                             *
-;* Description:                                                                                                                        *
-;*     This routine moves data to the RDR's.  The double-word that                     *
-;*     arg1 points to is loaded and moved into the staging register.           *
-;*     Then the STDIAG instruction for the RDR # in arg0 is called                     *
-;*     to move the data to the RDR.                                                                            *
-;*                                                                                                                                             *
-;* Arguments:                                                                                                                  *
-;*     arg0 = rdr number                                                                                                       *
-;*     arg1 = 64-bit value to write                                                                            *
-;*     %r24 - DR2 | DR2_SLOW_RET                                                                                       *
-;*     %r23 - original DR2 value                                                                                       *
-;*                                                                                                                                             *
-;* Returns:                                                                                                                            *
-;*     None                                                                                                                            *
-;*                                                                                                                                             *
-;* Register usage:                                                                                                             *
-;*                                                                                                                                             *
-;************************************************************************
+;***********************************************************************
+;*
+;* Name: perf_rdr_shift_out_W
+;*
+;* Description:
+;*     This routine moves data to the RDR's.  The double-word that
+;*     arg1 points to is loaded and moved into the staging register.
+;*     Then the STDIAG instruction for the RDR # in arg0 is called
+;*     to move the data to the RDR.
+;*
+;* Arguments:
+;*     arg0 = rdr number
+;*     arg1 = 64-bit value to write
+;*     %r24 - DR2 | DR2_SLOW_RET
+;*     %r23 - original DR2 value
+;*
+;* Returns:
+;*     None
+;*
+;* Register usage:
+;*
+;***********************************************************************
 
        .export perf_rdr_shift_out_W,code
 perf_rdr_shift_out_W:
@@ -587,24 +588,23 @@ perf_rdr_shift_out_W:
 
        depdi,z         1,DR2_SLOW_RET,1,%r24
        MFDIAG_2        (23)
-       or                   %r24,%r23,%r24
-       MTDIAG_2        (24)                    ; set DR2_SLOW_RET
-
-       MTDIAG_1        (25)                    ; data to the staging register
+       or              %r24,%r23,%r24
+       MTDIAG_2        (24)            ; set DR2_SLOW_RET
+       MTDIAG_1        (25)            ; data to the staging register
        shladd          arg0,2,%r0,%r1  ; %r1 = 4 * RDR number
-       blr                 %r1,%r0                 ; branch to 8-instruction sequence
+       blr                 %r1,%r0     ; branch to 8-instruction sequence
        nop
 
        ;
        ; RDR 0 write sequence
        ;
        sync                            ; RDR 0 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (0)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_W_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        ;
@@ -718,7 +718,7 @@ perf_rdr_shift_out_W:
        ;
        ; RDR 10 write sequence
        ;
-       sync    
+       sync
        ssm             0,0
        STDIAG          (10)
        STDIAG          (26)
@@ -862,7 +862,7 @@ perf_rdr_shift_out_W:
        ;
        ; RDR 22 write sequence
        ;
-       sync    
+       sync
        ssm             0,0
        STDIAG          (22)
        ssm             0,0
@@ -910,7 +910,7 @@ perf_rdr_shift_out_W:
        ;
        ; RDR 26 write sequence
        ;
-       sync    
+       sync
        ssm             0,0
        STDIAG          (10)
        STDIAG          (26)
@@ -958,7 +958,7 @@ perf_rdr_shift_out_W:
        ;
        ; RDR 30 write sequence
        ;
-       sync    
+       sync
        ssm             0,0
        STDIAG          (30)
        ssm             0,0
@@ -970,7 +970,7 @@ perf_rdr_shift_out_W:
        ;
        ; RDR 31 write sequence
        ;
-       sync                            
+       sync
        ssm             0,0
        STDIAG          (31)
        ssm             0,0
@@ -986,34 +986,32 @@ perf_rdr_shift_out_W_leave:
        .procend
 
 
-;**************************** CHRIS ***********************************
-
-;************************************************************************
-;*                                                                                                                                             *
-;* Name: rdr_shift_in_U                                                                                                        *
-;*                                                                                                                                             *
-;* Description:                                                                                                                        *
-;*     This routine shifts data in from the RDR in arg0 and returns            *
-;*     the result in ret0.  If the RDR is <= 64 bits in length, it                     *
-;*     is shifted shifted backup immediately.  This is to compensate           *
-;*     for RDR10 which has bits that preclude PDC stack operations                     *
-;*     when they are in the wrong state.                                                                       *
-;*                                                                                                                                             *
-;* Arguments:                                                                                                                  *
-;*     arg0 : rdr to be read                                                                                           *
-;*     arg1 : bit length of rdr                                                                                        *
-;*                                                                                                                                             *
-;* Returns:                                                                                                                            *
-;*     ret0 = next 64 bits of rdr data from staging register                           *
-;*                                                                                                                                             *
-;* Register usage:                                                                                                             *
-;*     arg0 : rdr to be read                                                                   *
-;*     arg1 : bit length of rdr                                                                *
-;*     %r24 - original DR2 value                                                                                       *
-;*     %r23 - DR2 | DR2_SLOW_RET                                                                                       *
-;*     %r1  - scratch                                                                                                          *
-;*                                                                                                                                             *
-;************************************************************************
+;***********************************************************************
+;*
+;* Name: rdr_shift_in_U
+;*
+;* Description:
+;*     This routine shifts data in from the RDR in arg0 and returns
+;*     the result in ret0.  If the RDR is <= 64 bits in length, it
+;*     is shifted shifted backup immediately.  This is to compensate
+;*     for RDR10 which has bits that preclude PDC stack operations
+;*     when they are in the wrong state.
+;*
+;* Arguments:
+;*     arg0 : rdr to be read
+;*     arg1 : bit length of rdr
+;*
+;* Returns:
+;*     ret0 = next 64 bits of rdr data from staging register
+;*
+;* Register usage:
+;*     arg0 : rdr to be read                                                                   
+;*     arg1 : bit length of rdr                                                                
+;*     %r24 - original DR2 value
+;*     %r23 - DR2 | DR2_SLOW_RET
+;*     %r1  - scratch
+;*
+;***********************************************************************
 
        .export perf_rdr_shift_in_U,code
 perf_rdr_shift_in_U:
@@ -1053,75 +1051,75 @@ perf_rdr_shift_in_U:
 ; Start of next 32-byte cacheline
 ;
        SFDIAG          (0)             ; RDR 0 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (0)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        SFDIAG          (1)             ; RDR 1 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (1)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        sync                            ; RDR 2 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (4)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        sync                            ; RDR 3 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (3)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 4 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (4)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        sync                            ; RDR 5 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (5)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        sync                            ; RDR 6 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (6)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        sync                            ; RDR 7 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (7)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
 
        b,n         perf_rdr_shift_in_U_leave
@@ -1134,95 +1132,95 @@ perf_rdr_shift_in_U:
        nop
 
        SFDIAG          (9)             ; RDR 9 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (9)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
 
        SFDIAG          (10)            ; RDR 10 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (10)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        SFDIAG          (11)            ; RDR 11 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (11)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        SFDIAG          (12)            ; RDR 12 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (12)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
 
        SFDIAG          (13)            ; RDR 13 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (13)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        SFDIAG          (14)            ; RDR 14 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (14)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        SFDIAG          (15)            ; RDR 15 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (15)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        sync                            ; RDR 16 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (16)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        SFDIAG          (17)            ; RDR 17 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (17)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        SFDIAG          (18)            ; RDR 18 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (18)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        b,n         perf_rdr_shift_in_U_leave
        nop
        nop
@@ -1233,86 +1231,86 @@ perf_rdr_shift_in_U:
        nop
 
        sync                            ; RDR 20 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (20)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        sync                            ; RDR 21 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (21)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        sync                            ; RDR 22 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (22)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        sync                            ; RDR 23 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (23)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        sync                            ; RDR 24 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (24)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        sync                            ; RDR 25 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (25)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        SFDIAG          (26)            ; RDR 26 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (26)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        SFDIAG          (27)            ; RDR 27 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (27)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        sync                            ; RDR 28 read sequence
-       ssm                     0,0
+       ssm             0,0
        SFDIAG          (28)
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        b,n         perf_rdr_shift_in_U_leave
-       ssm                     0,0
+       ssm             0,0
        nop
-       
+
        b,n         perf_rdr_shift_in_U_leave
        nop
        nop
@@ -1321,23 +1319,23 @@ perf_rdr_shift_in_U:
        nop
        nop
        nop
-       
+
        SFDIAG          (30)            ; RDR 30 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (30)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
-       
+
        SFDIAG          (31)            ; RDR 31 read sequence
-       ssm                     0,0
+       ssm             0,0
        MFDIAG_1        (28)
        shrpd           ret0,%r0,%sar,%r1
        MTDIAG_1        (1)
        STDIAG          (31)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_in_U_leave
        nop
 
@@ -1347,30 +1345,30 @@ perf_rdr_shift_in_U_leave:
        MTDIAG_2        (24)                    ; restore DR2
        .procend
 
-;************************************************************************
-;*                                                                                                                                             *
-;* Name: rdr_shift_out_U                                                                                               *
-;*                                                                                                                                             *
-;* Description:                                                                                                                        *
-;*     This routine moves data to the RDR's.  The double-word that                     *
-;*     arg1 points to is loaded and moved into the staging register.           *
-;*     Then the STDIAG instruction for the RDR # in arg0 is called                     *
-;*     to move the data to the RDR.                                                                            *
-;*                                                                                                                                             *
-;* Arguments:                                                                                                                  *
-;*     arg0 = rdr target                                                                                                       *
-;*     arg1 = buffer pointer                                                                                           *
-;*                                                                                                                                             *
-;* Returns:                                                                                                                            *
-;*     None                                                                                                                            *
-;*                                                                                                                                             *
-;* Register usage:                                                                                                             *
-;*     arg0 = rdr target                                                                                                       *
-;*     arg1 = buffer pointer                                                                                           *
-;*     %r24 - DR2 | DR2_SLOW_RET                                                                                       *
-;*     %r23 - original DR2 value                                                                                       *
-;*                                                                                                                                             *
-;************************************************************************
+;***********************************************************************
+;*
+;* Name: rdr_shift_out_U
+;*
+;* Description:
+;*     This routine moves data to the RDR's.  The double-word that
+;*     arg1 points to is loaded and moved into the staging register.
+;*     Then the STDIAG instruction for the RDR # in arg0 is called
+;*     to move the data to the RDR.
+;*
+;* Arguments:
+;*     arg0 = rdr target
+;*     arg1 = buffer pointer
+;*
+;* Returns:
+;*     None
+;*
+;* Register usage:
+;*     arg0 = rdr target
+;*     arg1 = buffer pointer
+;*     %r24 - DR2 | DR2_SLOW_RET
+;*     %r23 - original DR2 value
+;*
+;***********************************************************************
 
        .export perf_rdr_shift_out_U,code
 perf_rdr_shift_out_U:
@@ -1386,11 +1384,11 @@ perf_rdr_shift_out_U:
        depdi,z         1,DR2_SLOW_RET,1,%r24
        MFDIAG_2        (23)
        or              %r24,%r23,%r24
-       MTDIAG_2        (24)                    ; set DR2_SLOW_RET
+       MTDIAG_2        (24)            ; set DR2_SLOW_RET
 
-       MTDIAG_1        (25)                    ; data to the staging register
-       shladd           arg0,2,%r0,%r1 ; %r1 = 4 * RDR number
-       blr                 %r1,%r0                 ; branch to 8-instruction sequence
+       MTDIAG_1        (25)            ; data to the staging register
+       shladd          arg0,2,%r0,%r1  ; %r1 = 4 * RDR number
+       blr             %r1,%r0         ; branch to 8-instruction sequence
        nop
 
 ;
@@ -1398,291 +1396,291 @@ perf_rdr_shift_out_U:
 ;
 
        sync                            ; RDR 0 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (0)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 1 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (1)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 2 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (2)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 3 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (3)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 4 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (4)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 5 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (5)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 6 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (6)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 7 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (7)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 8 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (8)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 9 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (9)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 10 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (10)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 11 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (11)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 12 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (12)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 13 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (13)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 14 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (14)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 15 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (15)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 16 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (16)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 17 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (17)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 18 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (18)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 19 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (19)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 20 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (20)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 21 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (21)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 22 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (22)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 23 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (23)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 24 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (24)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 25 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (25)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 26 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (26)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 27 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (27)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 28 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (28)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 29 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (29)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 30 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (30)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
        sync                            ; RDR 31 write sequence
-       ssm                     0,0
+       ssm             0,0
        STDIAG          (31)
-       ssm                     0,0
+       ssm             0,0
        b,n         perf_rdr_shift_out_U_leave
        nop
-       ssm                     0,0
+       ssm             0,0
        nop
 
 perf_rdr_shift_out_U_leave:
index a8ed8d0..d9562fe 100644 (file)
@@ -2,6 +2,7 @@
  *    Imagine for use with the Onyx (PCX-U) CPU interface 
  *
  *    Copyright (C) 2001 Randolph Chung <tausq at parisc-linux.org>
+ *    Copyright (C) 2001 Hewlett-Packard (Grant Grundler)
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
index 8f4ad0c..6cf7407 100644 (file)
@@ -79,6 +79,8 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        while (nticks--) {
 #ifdef CONFIG_SMP
                smp_do_timer(regs);
+#else
+               update_process_times(user_mode(regs));
 #endif
                if (cpu == 0) {
                        write_seqlock(&xtime_lock);
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);
index 530235c..3eda1da 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <asm/uaccess.h>
 
 /* #define DEBUG_UNALIGNED 1 */
 
 #define RFMT "%08lx"
 #endif
 
+#define FIXUP_BRANCH(lbl) \
+       "\tldil L%%" #lbl ", %%r1\n"                    \
+       "\tldo R%%" #lbl "(%%r1), %%r1\n"               \
+       "\tbv,n %%r0(%%r1)\n"
+
 /* 1111 1100 0000 0000 0001 0011 1100 0000 */
 #define OPCODE1(a,b,c) ((a)<<26|(b)<<12|(c)<<6) 
 #define OPCODE2(a,b)   ((a)<<26|(b)<<1)
@@ -134,15 +140,19 @@ static int emulate_ldh(struct pt_regs *regs, int toreg)
 "1:    ldbs    0(%%sr1,%3), %%r20\n"
 "2:    ldbs    1(%%sr1,%3), %0\n"
 "      depw    %%r20, 23, 24, %0\n"
-"      cmpclr,= %%r0, %%r0, %1\n"
-"3:    ldo     -2(%%r0), %1\n"
-"      .section __ex_table,\"a\"\n"
+"      copy    %%r0, %1\n"
+"3:    \n"
+"      .section .fixup,\"ax\"\n"
+"4:    ldi     -2, %1\n"
+       FIXUP_BRANCH(3b)
+"      .previous\n"
+"      .section __ex_table,\"aw\"\n"
 #ifdef __LP64__
-"      .dword  1b,(3b-1b)\n"
-"      .dword  2b,(3b-2b)\n"
+"      .dword  1b,4b\n"
+"      .dword  2b,4b\n"
 #else
-"      .word   1b,(3b-1b)\n"
-"      .word   2b,(3b-2b)\n"
+"      .word   1b,4b\n"
+"      .word   2b,4b\n"
 #endif
 "      .previous\n"
        : "=r" (val), "=r" (ret)
@@ -175,15 +185,19 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
 "      subi    32,%%r19,%%r19\n"
 "      mtctl   %%r19,11\n"
 "      vshd    %0,%%r20,%0\n"
-"      cmpclr,= %%r0, %%r0, %1\n"
-"3:    ldo     -2(%%r0), %1\n"
-"      .section __ex_table,\"a\"\n"
+"      copy    %%r0, %1\n"
+"3:    \n"
+"      .section .fixup,\"ax\"\n"
+"4:    ldi     -2, %1\n"
+       FIXUP_BRANCH(3b)
+"      .previous\n"
+"      .section __ex_table,\"aw\"\n"
 #ifdef __LP64__
-"      .dword  1b,(3b-1b)\n"
-"      .dword  2b,(3b-2b)\n"
+"      .dword  1b,4b\n"
+"      .dword  2b,4b\n"
 #else
-"      .word   1b,(3b-1b)\n"
-"      .word   2b,(3b-2b)\n"
+"      .word   1b,4b\n"
+"      .word   2b,4b\n"
 #endif
 "      .previous\n"
        : "=r" (val), "=r" (ret)
@@ -222,15 +236,19 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "      subi    64,%%r19,%%r19\n"
 "      mtsar   %%r19\n"
 "      shrpd   %0,%%r20,%%sar,%0\n"
-"      cmpclr,= %%r0, %%r0, %1\n"
-"3:    ldo     -2(%%r0), %1\n"
-"      .section __ex_table,\"a\"\n"
+"      copy    %%r0, %1\n"
+"3:    \n"
+"      .section .fixup,\"ax\"\n"
+"4:    ldi     -2, %1\n"
+       FIXUP_BRANCH(3b)
+"      .previous\n"
+"      .section __ex_table,\"aw\"\n"
 #ifdef __LP64__
-"      .dword  1b,(3b-1b)\n"
-"      .dword  2b,(3b-2b)\n"
+"      .dword  1b,4b\n"
+"      .dword  2b,4b\n"
 #else
-"      .word   1b,(3b-1b)\n"
-"      .word   2b,(3b-2b)\n"
+"      .word   1b,4b\n"
+"      .word   2b,4b\n"
 #endif
 "      .previous\n"
        : "=r" (val), "=r" (ret)
@@ -250,17 +268,21 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "      mtsar   %%r19\n"
 "      vshd    %0,%1,%0\n"
 "      vshd    %1,%%r20,%1\n"
-"      cmpclr,= %%r0, %%r0, %2\n"
-"4:    ldo     -2(%%r0), %2\n"
-"      .section __ex_table,\"a\"\n"
+"      copy    %%r0, %2\n"
+"4:    \n"
+"      .section .fixup,\"ax\"\n"
+"5:    ldi     -2, %2\n"
+       FIXUP_BRANCH(4b)
+"      .previous\n"
+"      .section __ex_table,\"aw\"\n"
 #ifdef __LP64__
-"      .dword  1b,(4b-1b)\n"
-"      .dword  2b,(4b-2b)\n"
-"      .dword  3b,(4b-3b)\n"
+"      .dword  1b,5b\n"
+"      .dword  2b,5b\n"
+"      .dword  3b,5b\n"
 #else
-"      .word   1b,(4b-1b)\n"
-"      .word   2b,(4b-2b)\n"
-"      .word   3b,(4b-3b)\n"
+"      .word   1b,5b\n"
+"      .word   2b,5b\n"
+"      .word   3b,5b\n"
 #endif
 "      .previous\n"
        : "=r" (valh), "=r" (vall), "=r" (ret)
@@ -296,15 +318,19 @@ static int emulate_sth(struct pt_regs *regs, int frreg)
 "      extrw,u %1, 23, 8, %%r19\n"
 "1:    stb %1, 1(%%sr1, %2)\n"
 "2:    stb %%r19, 0(%%sr1, %2)\n"
-"      cmpclr,= %%r0, %%r0, %0\n"
-"3:    ldo     -2(%%r0), %0\n"
-"      .section __ex_table,\"a\"\n"
+"      copy    %%r0, %0\n"
+"3:    \n"
+"      .section .fixup,\"ax\"\n"
+"4:    ldi     -2, %0\n"
+       FIXUP_BRANCH(3b)
+"      .previous\n"
+"      .section __ex_table,\"aw\"\n"
 #ifdef __LP64__
-"      .dword  1b,(3b-1b)\n"
-"      .dword  2b,(3b-2b)\n"
+"      .dword  1b,4b\n"
+"      .dword  2b,4b\n"
 #else
-"      .word   1b,(3b-1b)\n"
-"      .word   2b,(3b-2b)\n"
+"      .word   1b,4b\n"
+"      .word   2b,4b\n"
 #endif
 "      .previous\n"
        : "=r" (ret)
@@ -346,15 +372,19 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
 "      or      %%r1, %%r21, %%r21\n"
 "      stw     %%r20,0(%%sr1,%2)\n"
 "      stw     %%r21,4(%%sr1,%2)\n"
-"      cmpclr,= %%r0, %%r0, %0\n"
-"3:    ldo     -2(%%r0), %0\n"
-"      .section __ex_table,\"a\"\n"
+"      copy    %%r0, %0\n"
+"3:    \n"
+"      .section .fixup,\"ax\"\n"
+"4:    ldi     -2, %0\n"
+       FIXUP_BRANCH(3b)
+"      .previous\n"
+"      .section __ex_table,\"aw\"\n"
 #ifdef __LP64__
-"      .dword  1b,(3b-1b)\n"
-"      .dword  2b,(3b-2b)\n"
+"      .dword  1b,4b\n"
+"      .dword  2b,4b\n"
 #else
-"      .word   1b,(3b-1b)\n"
-"      .word   2b,(3b-2b)\n"
+"      .word   1b,4b\n"
+"      .word   2b,4b\n"
 #endif
 "      .previous\n"
        : "=r" (ret)
@@ -399,19 +429,23 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "      or      %%r1, %%r21, %%r21\n"
 "3:    std     %%r20,0(%%sr1,%2)\n"
 "4:    std     %%r21,8(%%sr1,%2)\n"
-"      cmpclr,= %%r0, %%r0, %0\n"
-"5:    ldo     -2(%%r0), %0\n"
-"      .section __ex_table,\"a\"\n"
+"      copy    %%r0, %0\n"
+"5:    \n"
+"      .section .fixup,\"ax\"\n"
+"6:    ldi     -2, %0\n"
+       FIXUP_BRANCH(5b)
+"      .previous\n"
+"      .section __ex_table,\"aw\"\n"
 #ifdef __LP64__
-"      .dword  1b,(5b-1b)\n"
-"      .dword  2b,(5b-2b)\n"
-"      .dword  3b,(5b-3b)\n"
-"      .dword  4b,(5b-4b)\n"
+"      .dword  1b,6b\n"
+"      .dword  2b,6b\n"
+"      .dword  3b,6b\n"
+"      .dword  4b,6b\n"
 #else
-"      .word   1b,(5b-1b)\n"
-"      .word   2b,(5b-2b)\n"
-"      .word   3b,(5b-3b)\n"
-"      .word   4b,(5b-4b)\n"
+"      .word   1b,6b\n"
+"      .word   2b,6b\n"
+"      .word   3b,6b\n"
+"      .word   4b,6b\n"
 #endif
 "      .previous\n"
        : "=r" (ret)
@@ -438,21 +472,25 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "3:    stw     %1,0(%%sr1,%1)\n"
 "4:    stw     %%r1,4(%%sr1,%3)\n"
 "5:    stw     %2,8(%%sr1,%3)\n"
-"      cmpclr,= %%r0, %%r0, %0\n"
-"6:    ldo     -2(%%r0), %0\n"
-"      .section __ex_table,\"a\"\n"
+"      copy    %%r0, %0\n"
+"6:    \n"
+"      .section .fixup,\"ax\"\n"
+"7:    ldi     -2, %0\n"
+       FIXUP_BRANCH(6b)
+"      .previous\n"
+"      .section __ex_table,\"aw\"\n"
 #ifdef __LP64__
-"      .dword  1b,(6b-1b)\n"
-"      .dword  2b,(6b-2b)\n"
-"      .dword  3b,(6b-3b)\n"
-"      .dword  4b,(6b-4b)\n"
-"      .dword  5b,(6b-5b)\n"
+"      .dword  1b,7b\n"
+"      .dword  2b,7b\n"
+"      .dword  3b,7b\n"
+"      .dword  4b,7b\n"
+"      .dword  5b,7b\n"
 #else
-"      .word   1b,(6b-1b)\n"
-"      .word   2b,(6b-2b)\n"
-"      .word   3b,(6b-3b)\n"
-"      .word   4b,(6b-4b)\n"
-"      .word   5b,(6b-5b)\n"
+"      .word   1b,7b\n"
+"      .word   2b,7b\n"
+"      .word   3b,7b\n"
+"      .word   4b,7b\n"
+"      .word   5b,7b\n"
 #endif
 "      .previous\n"
        : "=r" (ret)
@@ -492,7 +530,6 @@ void handle_unaligned(struct pt_regs *regs)
                        show_regs(regs);
 #endif         
                }
-
                if (!unaligned_enabled)
                        goto force_sigbus;
        }
@@ -557,16 +594,6 @@ void handle_unaligned(struct pt_regs *regs)
                break;
        }
 
-       if (regs->isr != regs->sr[7])
-       {
-               printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
-                       regs->isr, regs->sr[7]);
-
-               /* don't kill him though, since he has appropriate access to the page, or we
-                * would never have gotten here.
-                */
-       }
-
        /* TODO: make this cleaner... */
        switch (regs->iir & OPCODE1_MASK)
        {
index abd7490..5e1e115 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/kallsyms.h>
 
 #include <asm/uaccess.h>
+#include <asm/assembly.h>
 
 #include <asm/unwind.h>
 
@@ -40,25 +42,27 @@ static struct unwind_table *unwind_tables, *unwind_tables_end;
 static inline const struct unwind_table_entry *
 find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
 {
-       const struct unwind_table_entry *e = 0;
+       const struct unwind_table_entry *e = NULL;
        unsigned long lo, hi, mid;
 
-       for (lo = 0, hi = table->length; lo < hi; )
-       {
-               mid = (lo + hi) / 2;
+       lo = 0; 
+       hi = table->length - 1; 
+       
+       while (lo <= hi) {
+               mid = (hi - lo) / 2 + lo;
                e = &table->table[mid];
                if (addr < e->region_start)
-                       hi = mid;
+                       hi = mid - 1;
                else if (addr > e->region_end)
                        lo = mid + 1;
                else
-                       break;
+                       return e;
        }
 
-       return e;
+       return NULL;
 }
 
-static inline const struct unwind_table_entry *
+static const struct unwind_table_entry *
 find_unwind_entry(unsigned long addr)
 {
        struct unwind_table *table = unwind_tables;
@@ -68,8 +72,7 @@ find_unwind_entry(unsigned long addr)
            addr <= kernel_unwind_table.end)
                e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
        else
-               for (; table; table = table->next)
-               {
+               for (; table; table = table->next) {
                        if (addr >= table->start && 
                            addr <= table->end)
                                e = find_unwind_entry_in_table(table, addr);
@@ -99,6 +102,11 @@ unwind_table_init(struct unwind_table *table, const char *name,
        table->next = NULL;
 
        for (; start <= end; start++) {
+               if (start < end && 
+                   start->region_end > (start+1)->region_start) {
+                       printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
+               }
+
                start->region_start += base_addr;
                start->region_end += base_addr;
        }
@@ -114,7 +122,7 @@ unwind_table_add(const char *name, unsigned long base_addr,
 
        table = kmalloc(sizeof(struct unwind_table), GFP_USER);
        if (table == NULL)
-               return 0;
+               return NULL;
        unwind_table_init(table, name, base_addr, gp, start, end);
        spin_lock_irqsave(&unwind_lock, flags);
        if (unwind_tables)
@@ -170,12 +178,40 @@ static void unwind_frame_regs(struct unwind_frame_info *info)
        int looking_for_rp, rpoffset = 0;
 
        e = find_unwind_entry(info->ip);
-       if (!e) {
+       if (e == NULL) {
                unsigned long sp;
                extern char _stext[], _etext[];
 
                dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
 
+#ifdef CONFIG_KALLSYMS
+               /* Handle some frequent special cases.... */
+               {
+                       char symname[KSYM_NAME_LEN+1];
+                       char *modname;
+                       unsigned long symsize, offset;
+
+                       kallsyms_lookup(info->ip, &symsize, &offset,
+                                       &modname, symname);
+
+                       dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
+
+                       if (strcmp(symname, "_switch_to_ret") == 0) {
+                               info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
+                               info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
+                               dbg("_switch_to_ret @ %lx - setting "
+                                   "prev_sp=%lx prev_ip=%lx\n", 
+                                   info->ip, info->prev_sp, 
+                                   info->prev_ip);
+                               return;
+                       } else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
+                                  strcmp(symname, "syscall_exit") == 0) {
+                               info->prev_ip = info->prev_sp = 0;
+                               return;
+                       }
+               }
+#endif
+
                /* Since we are doing the unwinding blind, we don't know if
                   we are adjusting the stack correctly or extracting the rp
                   correctly. The rp is checked to see if it belongs to the
@@ -185,30 +221,33 @@ static void unwind_frame_regs(struct unwind_frame_info *info)
                   modules. */
                sp = info->sp & ~63;
                do {
-                       info->prev_sp = sp - 64;
-
-                       /* FIXME: what happens if we unwind too far so that 
-                          sp no longer falls in a mapped kernel page? */
-#ifndef __LP64__
-                       info->prev_ip = *(unsigned long *)(info->prev_sp - 20);
-#else
-                       info->prev_ip = *(unsigned long *)(info->prev_sp - 16);
-#endif
+                       unsigned long tmp;
 
+                       info->prev_sp = sp - 64;
+                       info->prev_ip = 0;
+                       if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET))) 
+                               break;
+                       info->prev_ip = tmp;
                        sp = info->prev_sp;
                } while (info->prev_ip < (unsigned long)_stext ||
                         info->prev_ip > (unsigned long)_etext);
 
-               dbg("analyzing func @ %lx with no unwind info, setting prev_sp=%lx prev_ip=%lx\n", info->ip, info->prev_sp, info->prev_ip);
-       } else {
+               info->rp = 0;
 
-               dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, Save_RP = %d size = %u\n",
-                               e->region_start, e->region_end, e->Save_SP, e->Save_RP, e->Total_frame_size);
+               dbg("analyzing func @ %lx with no unwind info, setting "
+                   "prev_sp=%lx prev_ip=%lx\n", info->ip, 
+                   info->prev_sp, info->prev_ip);
+       } else {
+               dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
+                   "Save_RP = %d size = %u\n", e->region_start, 
+                   e->region_end, e->Save_SP, e->Save_RP, 
+                   e->Total_frame_size);
 
                looking_for_rp = e->Save_RP;
 
                for (npc = e->region_start; 
-                    (frame_size < (e->Total_frame_size << 3) || looking_for_rp) && 
+                    (frame_size < (e->Total_frame_size << 3) || 
+                     looking_for_rp) && 
                     npc < info->ip; 
                     npc += 4) {
 
@@ -219,22 +258,28 @@ static void unwind_frame_regs(struct unwind_frame_info *info)
                                /* ldo X(sp), sp, or stwm X,D(sp) */
                                frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
                                        ((insn & 0x3fff) >> 1);
-                               dbg("analyzing func @ %lx, insn=%08x @ %lx, frame_size = %ld\n", info->ip, insn, npc, frame_size);
-                       } else if ((insn & 0xffe00008) == 0x7ec00008) {
+                               dbg("analyzing func @ %lx, insn=%08x @ "
+                                   "%lx, frame_size = %ld\n", info->ip,
+                                   insn, npc, frame_size);
+                       } else if ((insn & 0xffe00008) == 0x73c00008) {
                                /* std,ma X,D(sp) */
                                frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
                                        (((insn >> 4) & 0x3ff) << 3);
-                               dbg("analyzing func @ %lx, insn=%08x @ %lx, frame_size = %ld\n", info->ip, insn, npc, frame_size);
+                               dbg("analyzing func @ %lx, insn=%08x @ "
+                                   "%lx, frame_size = %ld\n", info->ip,
+                                   insn, npc, frame_size);
                        } else if (insn == 0x6bc23fd9) { 
                                /* stw rp,-20(sp) */
                                rpoffset = 20;
                                looking_for_rp = 0;
-                               dbg("analyzing func @ %lx, insn=stw rp,-20(sp) @ %lx\n", info->ip, npc);
+                               dbg("analyzing func @ %lx, insn=stw rp,"
+                                   "-20(sp) @ %lx\n", info->ip, npc);
                        } else if (insn == 0x0fc212c1) {
                                /* std rp,-16(sr0,sp) */
                                rpoffset = 16;
                                looking_for_rp = 0;
-                               dbg("analyzing func @ %lx, insn=std rp,-16(sp) @ %lx\n", info->ip, npc);
+                               dbg("analyzing func @ %lx, insn=std rp,"
+                                   "-16(sp) @ %lx\n", info->ip, npc);
                        }
                }
 
@@ -244,7 +289,9 @@ static void unwind_frame_regs(struct unwind_frame_info *info)
                info->prev_ip = info->rp;
                info->rp = 0;
 
-               dbg("analyzing func @ %lx, setting prev_sp=%lx prev_ip=%lx\n", info->ip, info->prev_sp, info->prev_ip);
+               dbg("analyzing func @ %lx, setting prev_sp=%lx "
+                   "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp, 
+                   info->prev_ip, npc);
        }
 }
 
@@ -257,7 +304,8 @@ void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
        info->ip = ip;
        info->rp = rp;
 
-       dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", t ? (int)t->pid : 0, info->sp, info->ip);
+       dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", 
+           t ? (int)t->pid : -1, info->sp, info->ip);
 }
 
 void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
@@ -285,7 +333,9 @@ int unwind_once(struct unwind_frame_info *next_frame)
        next_frame->prev_sp = 0;
        next_frame->prev_ip = 0;
 
-       dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", (int)next_frame->t->pid, next_frame->sp, next_frame->ip);
+       dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", 
+           next_frame->t ? (int)next_frame->t->pid : -1, 
+           next_frame->sp, next_frame->ip);
 
        return 0;
 }
index 7322c7e..3ab95fd 100644 (file)
@@ -2,6 +2,6 @@
 # Makefile for parisc-specific library files
 #
 
-lib-y  := lusercopy.o bitops.o checksum.o io.o memset.o
+lib-y  := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o memcpy.o
 
 lib-$(CONFIG_SMP) += debuglocks.o
index abd29ac..c402e75 100644 (file)
 #include <asm/string.h>
 #include <asm/uaccess.h>
 
+#define addc(_t,_r)                     \
+       __asm__ __volatile__ (          \
+"       add             %0, %1, %0\n"   \
+"       addc            %0, %%r0, %0\n" \
+       : "=r"(_t)                      \
+       : "r"(_r), "0"(_t));
+
 static inline unsigned short from32to16(unsigned int x)
 {
        /* 32 bits --> 16 bits + carry */
@@ -56,16 +63,25 @@ static inline unsigned int do_csum(const unsigned char * buff, int len)
                }
                count >>= 1;            /* nr of 32-bit words.. */
                if (count) {
-                       unsigned int carry = 0;
-                       do {
+                       while (count >= 4) {
+                               unsigned int r1, r2, r3, r4;
+                               r1 = *(unsigned int *)(buff + 0);
+                               r2 = *(unsigned int *)(buff + 4);
+                               r3 = *(unsigned int *)(buff + 8);
+                               r4 = *(unsigned int *)(buff + 12);
+                               addc(result, r1);
+                               addc(result, r2);
+                               addc(result, r3);
+                               addc(result, r4);
+                               count -= 4;
+                               buff += 16;
+                       }
+                       while (count) {
                                unsigned int w = *(unsigned int *) buff;
                                count--;
                                buff += 4;
-                               result += carry;
-                               result += w;
-                               carry = (w > result);
-                       } while (count);
-                       result += carry;
+                               addc(result, w);
+                       }
                        result = (result & 0xffff) + (result >> 16);
                }
                if (len & 2) {
@@ -77,7 +93,7 @@ static inline unsigned int do_csum(const unsigned char * buff, int len)
                result += le16_to_cpu(*buff);
        result = from32to16(result);
        if (odd)
-               result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+               result = swab16(result);
 out:
        return result;
 }
@@ -88,12 +104,8 @@ out:
 unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
 {
        unsigned int result = do_csum(buff, len);
-
-       /* add in old sum, and carry.. */
-       result += sum;
-       if(sum > result)
-               result += 1;
-       return result;
+       addc(result, sum);
+       return from32to16(result);
 }
 
 EXPORT_SYMBOL(csum_partial);
index 5166a93..5ac3eb0 100644 (file)
  *    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
+ *
+ *    We use pdc_printf() throughout the file for all output messages, to avoid
+ *    losing messages because of disabled interrupts. Since we're using these
+ *    messages for debugging purposes, it makes sense not to send them to the
+ *    linux console.
  */
 
 
 #include <linux/spinlock.h>
 #include <linux/hardirq.h>     /* in_interrupt() */
 #include <asm/system.h>
+#include <asm/hardirq.h>       /* in_interrupt() */
+#include <asm/pdc.h>
 
 #undef INIT_STUCK
 #define INIT_STUCK 1L << 30
 
 #ifdef CONFIG_DEBUG_SPINLOCK
 
+
 void _dbg_spin_lock(spinlock_t * lock, const char *base_file, int line_no)
 {
        volatile unsigned int *a;
@@ -59,12 +67,14 @@ try_again:
         * <tausq> __ldcw() returns 1 if we get the lock; otherwise we
         *      spin until the value of the lock changes, or we time out.
         */
+       mb();
        a = __ldcw_align(lock);
        while (stuck && (__ldcw(a) == 0))
                while ((*a == 0) && --stuck);
+       mb();
 
        if (unlikely(stuck <= 0)) {
-               printk(KERN_WARNING
+               pdc_printf(
                        "%s:%d: spin_lock(%s/%p) stuck in %s at %p(%d)"
                        " owned by %s:%d in %s at %p(%d)\n",
                        base_file, line_no, lock->module, lock,
@@ -84,7 +94,7 @@ try_again:
        lock->bline = line_no;
 
        if (unlikely(printed)) {
-               printk(KERN_WARNING
+               pdc_printf(
                        "%s:%d: spin_lock grabbed in %s at %p(%d) %ld ticks\n",
                        base_file, line_no, current->comm, inline_pc,
                        cpu, jiffies - started);
@@ -94,21 +104,28 @@ try_again:
 void _dbg_spin_unlock(spinlock_t * lock, const char *base_file, int line_no)
 {
        CHECK_LOCK(lock);
-       volatile unsigned int *a = __ldcw_align(lock);
+       volatile unsigned int *a;
+       mb();
+       a = __ldcw_align(lock);
        if (unlikely((*a != 0) && lock->babble)) {
                lock->babble--;
-               printk(KERN_WARNING
+               pdc_printf(
                        "%s:%d: spin_unlock(%s:%p) not locked\n",
                        base_file, line_no, lock->module, lock);
        }
        *a = 1; 
+       mb();
 }
 
 int _dbg_spin_trylock(spinlock_t * lock, const char *base_file, int line_no)
 {
        int ret;
-       volatile unsigned int *a = __ldcw_align(lock);
-       if ((ret = (__ldcw(a) != 0))) {
+       volatile unsigned int *a;
+       mb();
+       a = __ldcw_align(lock);
+       ret = (__ldcw(a) != 0);
+       mb();
+       if (ret) {
                lock->oncpu = smp_processor_id();
                lock->previous = __builtin_return_address(0);
                lock->task = current;
@@ -150,7 +167,7 @@ void _dbg_write_lock(rwlock_t *rw, const char *bfile, int bline)
        int cpu = smp_processor_id();
        
        if(unlikely(in_interrupt())) {  /* acquiring write lock in interrupt context, bad idea */
-               printk(KERN_WARNING "write_lock caller: %s:%d, IRQs enabled,\n", bfile, bline);
+               pdc_printf("write_lock caller: %s:%d, IRQs enabled,\n", bfile, bline);
                BUG();
        }
 
@@ -167,7 +184,7 @@ retry:
                
                stuck--;
                if ((unlikely(stuck <= 0)) && (rw->counter < 0)) {
-                       printk(KERN_WARNING
+                       pdc_printf(
                                "%s:%d: write_lock stuck on writer"
                                " in %s at %p(%d) %ld ticks\n",
                                bfile, bline, current->comm, inline_pc,
@@ -176,7 +193,7 @@ retry:
                        printed = 1;
                }
                else if (unlikely(stuck <= 0)) {
-                       printk(KERN_WARNING
+                       pdc_printf(
                                "%s:%d: write_lock stuck on reader"
                                " in %s at %p(%d) %ld ticks\n",
                                bfile, bline, current->comm, inline_pc,
@@ -194,13 +211,47 @@ retry:
        rw->counter = -1; /* remember we are locked */
 
        if (unlikely(printed)) {
-               printk(KERN_WARNING
+               pdc_printf(
                        "%s:%d: write_lock grabbed in %s at %p(%d) %ld ticks\n",
                        bfile, bline, current->comm, inline_pc,
                        cpu, jiffies - started);
        }
 }
 
+int _dbg_write_trylock(rwlock_t *rw, const char *bfile, int bline)
+{
+#if 0
+       void *inline_pc = __builtin_return_address(0);
+       int cpu = smp_processor_id();
+#endif
+       
+       if(unlikely(in_interrupt())) {  /* acquiring write lock in interrupt context, bad idea */
+               pdc_printf("write_lock caller: %s:%d, IRQs enabled,\n", bfile, bline);
+               BUG();
+       }
+
+       /* Note: if interrupts are disabled (which is most likely), the printk
+       will never show on the console. We might need a polling method to flush
+       the dmesg buffer anyhow. */
+       
+       _raw_spin_lock(&rw->lock);
+
+       if(rw->counter != 0) {
+               /* this basically never happens */
+               _raw_spin_unlock(&rw->lock);
+               
+               
+               return 0;
+       }
+
+       /* got it.  now leave without unlocking */
+       rw->counter = -1; /* remember we are locked */
+#if 0
+       pdc_printf("%s:%d: try write_lock grabbed in %s at %p(%d)\n",
+                  bfile, bline, current->comm, inline_pc, cpu);
+#endif
+}
+
 void _dbg_read_lock(rwlock_t * rw, const char *bfile, int bline)
 {
 #if 0
@@ -215,7 +266,7 @@ void _dbg_read_lock(rwlock_t * rw, const char *bfile, int bline)
 
        rw->counter++;
 #if 0
-       printk(KERN_WARNING
+       pdc_printf(
                "%s:%d: read_lock grabbed in %s at %p(%d) %ld ticks\n",
                bfile, bline, current->comm, inline_pc,
                cpu, jiffies - started);
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
index 72c9615..a050985 100644 (file)
        mtsp        %r1,%sr1
        .endm
 
-       /*
-        * unsigned long
-        * lcopy_to_user(void *to, const void *from, unsigned long n)
-        *
-        * Returns 0 for success.
-        * otherwise, returns number of bytes not transferred.
-        */
-
-       .export lcopy_to_user,code
-lcopy_to_user:
-       .proc
-       .callinfo NO_CALLS
-       .entry
-       comib,=,n   0,%r24,$lctu_done
-       get_sr
-$lctu_loop:
-       ldbs,ma     1(%r25),%r1
-       addib,<>    -1,%r24,$lctu_loop
-1:      stbs,ma     %r1,1(%sr1,%r26)
-$lctu_done:
-       bv          %r0(%r2)
-       copy        %r24,%r28
-       .exit
-
-2:      b $lctu_done
-       ldo         1(%r24),%r24
-
-       .section __ex_table,"a"
-#ifdef __LP64__
-       .dword      1b,(2b-1b)
-#else
-       .word       1b,(2b-1b)
-#endif
-       .previous
-
-       .procend
-
-       /*
-        * unsigned long
-        * lcopy_from_user(void *to, const void *from, unsigned long n)
-        *
-        * Returns 0 for success.
-        * otherwise, returns number of bytes not transferred.
-        *
-        * NOTE: This routine will also zero any bytes in the
-        *       destination that were not copied due to a fault.
-        *
-        */
-
-       .export lcopy_from_user,code
-lcopy_from_user:
-       .proc
-       .callinfo NO_CALLS
-       .entry
-       comib,=,n   0,%r24,$lcfu_done
-       get_sr
-$lcfu_loop:
-1:      ldbs,ma     1(%sr1,%r25),%r1
-       addib,<>    -1,%r24,$lcfu_loop
-       stbs,ma     %r1,1(%r26)
-$lcfu_done:
-       bv          %r0(%r2)
-       copy        %r24,%r28
-       .exit
-
-2:      copy        %r24,%r23
-$lcfu_zero_loop:
-       addib,<>    -1,%r23,$lcfu_zero_loop
-       stbs,ma     %r0,1(%r26)
-       b           $lcfu_done
-       nop
-
-       .section __ex_table,"a"
-#ifdef __LP64__
-       .dword      1b,(2b-1b)
-#else
-       .word       1b,(2b-1b)
-#endif
-       .previous
-
-       .procend
-
-       /*
-        * unsigned long
-        * lcopy_in_user(void *to, const void *from, unsigned long n)
-        *
-        * Returns 0 for success.
-        * otherwise, returns number of bytes not transferred.
-        */
-
-       .export lcopy_in_user,code
-lcopy_in_user:
-       .proc
-       .callinfo NO_CALLS
-       .entry
-       comib,=,n   0,%r24,$lciu_done
-       get_sr
-$lciu_loop:
-       ldbs,ma     1(%sr1,%r25),%r1
-       addib,<>    -1,%r24,$lciu_loop
-1:      stbs,ma     %r1,1(%sr1,%r26)
-$lciu_done:
-       bv          %r0(%r2)
-       copy        %r24,%r28
-       .exit
-
-2:      b $lciu_done
-       ldo         1(%r24),%r24
-
-       .section __ex_table,"a"
-#ifdef __LP64__
-       .dword      1b,(2b-1b)
-#else
-       .word       1b,(2b-1b)
-#endif
-       .previous
-
-       .procend
+       .macro fixup_branch lbl
+       ldil        L%\lbl, %r1
+       ldo         R%\lbl(%r1), %r1
+       bv          %r0(%r1)
+       .endm
 
        /*
         * long lstrncpy_from_user(char *dst, const char *src, long n)
@@ -201,16 +88,18 @@ $lsfu_exit:
        nop
        .exit
 
-3:      b           $lsfu_exit
+       .section .fixup,"ax"
+3:      fixup_branch $lsfu_exit
        ldi         -EFAULT,%r28
+       .previous
 
-       .section __ex_table,"a"
+       .section __ex_table,"aw"
 #ifdef __LP64__
-       .dword      1b,(3b-1b)
-       .dword      2b,(3b-2b)
+       .dword      1b,3b
+       .dword      2b,3b
 #else
-       .word       1b,(3b-1b)
-       .word       2b,(3b-2b)
+       .word       1b,3b
+       .word       2b,3b
 #endif
        .previous
 
@@ -239,14 +128,16 @@ $lclu_done:
        copy        %r25,%r28
        .exit
 
-2:      b $lclu_done
+       .section .fixup,"ax"
+2:      fixup_branch $lclu_done
        ldo        1(%r25),%r25
+       .previous
 
-       .section __ex_table,"a"
+       .section __ex_table,"aw"
 #ifdef __LP64__
-       .dword      1b,(2b-1b)
+       .dword      1b,2b
 #else
-       .word       1b,(2b-1b)
+       .word       1b,2b
 #endif
        .previous
 
@@ -282,16 +173,18 @@ $lslen_nzero:
        b           $lslen_done
        ldo         1(%r26),%r26 /* special case for N == 0 */
 
-3:      b           $lslen_done
+       .section .fixup,"ax"
+3:      fixup_branch $lslen_done
        copy        %r24,%r26    /* reset r26 so 0 is returned on fault */
+       .previous
 
-       .section __ex_table,"a"
+       .section __ex_table,"aw"
 #ifdef __LP64__
-       .dword      1b,(3b-1b)
-       .dword      2b,(3b-2b)
+       .dword      1b,3b
+       .dword      2b,3b
 #else
-       .word       1b,(3b-1b)
-       .word       2b,(3b-2b)
+       .word       1b,3b
+       .word       2b,3b
 #endif
        .previous
 
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
index d52b3a0..fd1c772 100644 (file)
@@ -36,6 +36,9 @@
 
 #define BITSSET                0x1c0   /* for identifying LDCW */
 
+
+DEFINE_PER_CPU(struct exception_data, exception_data);
+
 /*
  * parisc_acctyp(unsigned int inst) --
  *    Given a PA-RISC memory access instruction, determine if the
@@ -230,17 +233,17 @@ bad_area:
 no_context:
 
        if (!user_mode(regs)) {
-
                fix = search_exception_tables(regs->iaoq[0]);
 
                if (fix) {
+                       struct exception_data *d;
 
-                       if (fix->skip & 1) 
-                               regs->gr[8] = -EFAULT;
-                       if (fix->skip & 2)
-                               regs->gr[9] = 0;
+                       d = &__get_cpu_var(exception_data);
+                       d->fault_ip = regs->iaoq[0];
+                       d->fault_space = regs->isr;
+                       d->fault_addr = regs->ior;
 
-                       regs->iaoq[0] += ((fix->skip) & ~3);
+                       regs->iaoq[0] = ((fix->fixup) & ~3);
 
                        /*
                         * NOTE: In some cases the faulting instruction
index bf13619..ee9b1f0 100644 (file)
@@ -74,37 +74,6 @@ config ENET_BIG_BUFFERS
          Allocate large buffers for MPC8xx Etherenet.  Increases throughput
          and decreases the likelihood of dropped packets, but costs memory.
 
-config SMC2_UART
-       bool "Use SMC2 for UART"
-       help
-         If you would like to use SMC2 as a serial port, say Y here.
-
-         If in doubt, say Y here.
-
-config ALTSMC2
-       bool "Use Alternate SMC2 I/O (823/850)"
-       depends on SMC2_UART
-       help
-         If you have an MPC823 or MPC850 and would like to use the alternate
-         SMC2 for I/O, say Y here.
-
-         If in doubt, say N here.
-
-config CONS_SMC2
-       bool "Use SMC2 for Console"
-       depends on SMC2_UART
-       help
-         If you are going to have a serial console on your device and are
-         using SMC2 for your serial port, say Y here, else say N.
-
-config USE_SCC_IO
-       bool "Enable SCC2 and SCC3 for UART"
-       help
-         If your MPC8xx board has other SCC ports that you would like to use
-         for for a serial port, say Y here.
-
-         If in doubt, say N here.
-
 config HTDMSOUND
        bool "Embedded Planet HIOX Audio"
        depends on SOUND=y
@@ -134,13 +103,36 @@ config 8xx_CPU6
 
          If in doubt, say N here.
 
-config UCODE_PATCH
-       bool "I2C/SPI Microcode Patch"
+choice
+       prompt "Microcode patch selection"
+       default NO_UCODE_PATCH
+       help
+         Help not implemented yet, coming soon.
+
+config NO_UCODE_PATCH
+       bool "None"
+
+config USB_SOF_UCODE_PATCH
+       bool "USB SOF patch"
+       help
+         Help not implemented yet, coming soon.
+
+config I2C_SPI_UCODE_PATCH
+       bool "I2C/SPI relocation patch"
        help
-         Motorola releases microcode updates for their 8xx CPM modules.  The
-         microcode update file has updates for IIC, SMC and USB.  Currently only
-         the USB update is available by default, if the MPC8xx USB option is
-         enabled.  If in doubt, say 'N' here.
+         Help not implemented yet, coming soon.
+
+config I2C_SPI_SMC1_UCODE_PATCH
+       bool "I2C/SPI/SMC1 relocation patch"
+       help
+         Help not implemented yet, coming soon.
+
+endchoice
+
+config UCODE_PATCH
+       bool
+       default y
+       depends on !NO_UCODE_PATCH
 
 endmenu
 
index 7e51219..d876018 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux MPC8xx ppc-specific parts of comm processor
 #
 
-obj-y                  := commproc.o uart.o
+obj-y                  := commproc.o
 
 obj-$(CONFIG_FEC_ENET) += fec.o
 obj-$(CONFIG_SCC_ENET) += enet.o
index 5c7c914..b2ebae8 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
+#include <linux/bitops.h>
 #ifdef CONFIG_FEC_PACKETHOOK
 #include <linux/pkthook.h>
 #endif
@@ -52,7 +53,6 @@
 #include <asm/pgtable.h>
 #include <asm/mpc8xx.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/commproc.h>
 
@@ -1684,7 +1684,7 @@ static int __init fec_enet_init(void)
 
        /* Install our interrupt handler.
        */
-       if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
+       if (request_irq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
                panic("Could not allocate FEC IRQ!");
 
 #ifdef CONFIG_RPXCLASSIC
@@ -1705,7 +1705,7 @@ static int __init fec_enet_init(void)
        ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
                (0x80000000 >> PHY_INTERRUPT);
 
-       if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
+       if (request_irq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
                panic("Could not allocate MII IRQ!");
 #endif
 
index 68a51ee..312af07 100644 (file)
 #include <asm/8xx_immap.h>
 #include <asm/commproc.h>
 
-/* Define this to get SMC patches as well.  You need to modify the uart
- * driver as well......
-#define USE_SMC_PATCH 1
+/*
+ * I2C/SPI relocation patch arrays.
  */
 
-#ifdef CONFIG_USB_MPC8xx
-#define USE_USB_SOF_PATCH
-#endif
+#ifdef CONFIG_I2C_SPI_UCODE_PATCH
 
-#ifdef USE_IIC_PATCH
-#define PATCH_DEFINED
-       /* IIC/SPI */
 uint patch_2000[] = {
        0x7FFFEFD9,
        0x3FFD0000,
@@ -183,11 +177,12 @@ uint patch_2f00[] = {
 };
 #endif
 
-#ifdef USE_SMC_PATCH
-#define PATCH_DEFINED
-/* SMC2/IIC/SPI Patch */
-/* This is the area from 0x2000 to 0x23ff.
-*/
+/*
+ * I2C/SPI/SMC1 relocation patch arrays.
+ */
+
+#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
+
 uint patch_2000[] = {
        0x3fff0000,
        0x3ffd0000,
@@ -511,8 +506,6 @@ uint patch_2000[] = {
        0x6079e2bb
 };
 
-       /* This is from 0x2f00 to 0x2fff
-       */
 uint patch_2f00[] = {
        0x30303030,
        0x3e3e3434,
@@ -581,8 +574,6 @@ uint patch_2f00[] = {
 };
 
 uint patch_2e00[] = {
-       /* This is from 0x2e00 to 0x2e3c
-       */
        0x27eeeeee,
        0xeeeeeeee,
        0xeeeeeeee,
@@ -602,8 +593,12 @@ uint patch_2e00[] = {
 };
 #endif
 
-#ifdef USE_USB_SOF_PATCH
-#define PATCH_DEFINED
+/*
+ *  USB SOF patch arrays.
+ */
+
+#ifdef CONFIG_USB_SOF_UCODE_PATCH
+
 uint patch_2000[] = {
        0x7fff0000,
        0x7ffd0000,
@@ -626,33 +621,21 @@ uint patch_2f00[] = {
 };
 #endif
 
-/* Load the microcode patch.  This is called early in the CPM initialization
- * with the controller in the reset state.  We enable the processor after
- * we load the patch.
- */
 void
 cpm_load_patch(volatile immap_t *immr)
 {
-#ifdef PATCH_DEFINED
-       volatile uint           *dp;
+       volatile uint           *dp;            /* Dual-ported RAM. */
        volatile cpm8xx_t       *commproc;
        volatile iic_t          *iip;
        volatile spi_t          *spp;
+       volatile smc_uart_t     *smp;
        int     i;
 
        commproc = (cpm8xx_t *)&immr->im_cpm;
 
-       /* We work closely with commproc.c.  We know it only allocates
-        * from data only space.
-        * For this particular patch, we only use the bottom 512 bytes
-        * and the upper 256 byte extension.  We will use the space
-        * starting at 1K for the relocated parameters, as the general
-        * CPM allocation won't come from that area.
-        */
+#ifdef CONFIG_USB_SOF_UCODE_PATCH
        commproc->cp_rccr = 0;
 
-       /* Copy the patch into DPRAM.
-       */
        dp = (uint *)(commproc->cp_dpmem);
        for (i=0; i<(sizeof(patch_2000)/4); i++)
                *dp++ = patch_2000[i];
@@ -661,29 +644,26 @@ cpm_load_patch(volatile immap_t *immr)
        for (i=0; i<(sizeof(patch_2f00)/4); i++)
                *dp++ = patch_2f00[i];
 
-#ifdef USE_USB_SOF_PATCH
-#if 0 /* usb patch should not relocate iic */
-       iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
-#define RPBASE 0x0030
-       iip->iic_rpbase = RPBASE;
+       commproc->cp_rccr = 0x0009;
 
-       /* Put SPI above the IIC, also 32-byte aligned.
-       */
-       i = (RPBASE + sizeof(iic_t) + 31) & ~31;
-       spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
-       spp->spi_rpbase = i;
-#endif
+       printk("USB SOF microcode patch installed\n");
+#endif /* CONFIG_USB_SOF_UCODE_PATCH */
 
-       /* Enable uCode fetches from DPRAM. */
-       commproc->cp_rccr = 0x0009;
+#if defined(CONFIG_I2C_SPI_UCODE_PATCH) || \
+    defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
+
+       commproc->cp_rccr = 0;
 
-       printk("USB uCode patch installed\n");
-#endif /* USE_USB_SOF_PATCH */
+       dp = (uint *)(commproc->cp_dpmem);
+       for (i=0; i<(sizeof(patch_2000)/4); i++)
+               *dp++ = patch_2000[i];
 
-#if defined(USE_SMC_PATCH) || defined(USE_IIC_PATCH)
+       dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
+       for (i=0; i<(sizeof(patch_2f00)/4); i++)
+               *dp++ = patch_2f00[i];
 
        iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
-#define RPBASE 0x0400
+# define RPBASE 0x0500
        iip->iic_rpbase = RPBASE;
 
        /* Put SPI above the IIC, also 32-byte aligned.
@@ -692,58 +672,46 @@ cpm_load_patch(volatile immap_t *immr)
        spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
        spp->spi_rpbase = i;
 
-#ifdef USE_SMC_PATCH
+# if defined(CONFIG_I2C_SPI_UCODE_PATCH)
+       commproc->cp_cpmcr1 = 0x802a;
+       commproc->cp_cpmcr2 = 0x8028;
+       commproc->cp_cpmcr3 = 0x802e;
+       commproc->cp_cpmcr4 = 0x802c;
+       commproc->cp_rccr = 1;
+
+       printk("I2C/SPI microcode patch installed.\n");
+# endif /* CONFIG_I2C_SPI_UCODE_PATCH */
+
+# if defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
+
        dp = (uint *)&(commproc->cp_dpmem[0x0e00]);
        for (i=0; i<(sizeof(patch_2e00)/4); i++)
                *dp++ = patch_2e00[i];
 
-       /* Enable the traps to get to it.
-       */
        commproc->cp_cpmcr1 = 0x8080;
        commproc->cp_cpmcr2 = 0x808a;
        commproc->cp_cpmcr3 = 0x8028;
        commproc->cp_cpmcr4 = 0x802a;
-
-       /* Enable uCode fetches from DPRAM.
-       */
        commproc->cp_rccr = 3;
-#endif
-
-#ifdef USE_IIC_PATCH
-       /* Enable the traps to get to it.
-       */
-       commproc->cp_cpmcr1 = 0x802a;
-       commproc->cp_cpmcr2 = 0x8028;
-       commproc->cp_cpmcr3 = 0x802e;
-       commproc->cp_cpmcr4 = 0x802c;
 
-       /* Enable uCode fetches from DPRAM.
-       */
-       commproc->cp_rccr = 1;
-
-       printk("I2C uCode patch installed\n");
-#endif
+       smp = (smc_uart_t *)&commproc->cp_dparam[PROFF_SMC1];
+       smp->smc_rpbase = 0x1FC0;
 
-       /* Relocate the IIC and SPI parameter areas.  These have to
-        * aligned on 32-byte boundaries.
-        */
-       iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
-       iip->iic_rpbase = RPBASE;
-
-       /* Put SPI above the IIC, also 32-byte aligned.
-       */
-       i = (RPBASE + sizeof(iic_t) + 31) & ~31;
-       spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
-       spp->spi_rpbase = i;
+       printk("I2C/SPI/SMC1 microcode patch installed.\n");
+# endif /* CONFIG_I2C_SPI_SMC1_UCODE_PATCH) */
 
-#endif /* USE_SMC_PATCH || USE_IIC_PATCH */
-#endif /* PATCH_DEFINED */
+#endif /* some variation of the I2C/SPI patch was selected */
 }
 
+/*
+ *  Take this entire routine out, since no one calls it and its 
+ * logic is suspect.
+ */
+
+#if 0
 void
 verify_patch(volatile immap_t *immr)
 {
-#ifdef PATCH_DEFINED
        volatile uint           *dp;
        volatile cpm8xx_t       *commproc;
        int i;
@@ -772,6 +740,5 @@ verify_patch(volatile immap_t *immr)
                }
 
        commproc->cp_rccr = 0x0009;
-#endif /* PATCH_DEFINED */
 }
-
+#endif
index 0df2814..d2e1eea 100644 (file)
@@ -53,18 +53,6 @@ config BDI_SWITCH
          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
@@ -78,7 +66,7 @@ config SERIAL_TEXT_DEBUG
 
 config PPC_OCP
        bool
-       depends on IBM_OCP || FSL_OCP
+       depends on IBM_OCP || FSL_OCP || XILINX_OCP
        default y
 
 endmenu
index 7c4fb8f..d0161ac 100644 (file)
@@ -27,6 +27,7 @@
 
        .text
 
+#ifdef CONFIG_6xx
        .globl  disable_6xx_mmu
 disable_6xx_mmu:
        /* Establish default MSR value, exception prefix 0xFFF.
@@ -94,6 +95,7 @@ disable_6xx_l1cache:
        sync
        isync
        blr
+#endif
 
        .globl  _setup_L2CR
 _setup_L2CR:
index 9d088a5..d4077e6 100644 (file)
@@ -2,9 +2,22 @@
 # Makefile for some libs needed by zImage.
 #
 
-CFLAGS_kbd.o   += -Idrivers/char
+CFLAGS_kbd.o   := -Idrivers/char
+CFLAGS_vreset.o := -I$(srctree)/arch/ppc/boot/include
 
-lib-y := $(addprefix ../../../../lib/zlib_inflate/, \
-           infblock.o infcodes.o inffast.o inflate.o inftrees.o infutil.o)
-lib-y += div64.o
+zlib  := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
+        
+lib-y += $(zlib:.c=.o) div64.o
 lib-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o
+
+
+# zlib files needs header from their original place
+EXTRA_CFLAGS += -Ilib/zlib_inflate
+
+quiet_cmd_copy_zlib = COPY    $@
+      cmd_copy_zlib = cat $< > $@
+
+$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
+       $(call cmd,copy_zlib)
+
+clean-files := $(zlib)
index 8615d5f..3865f3f 100644 (file)
@@ -218,7 +218,7 @@ load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *b
        puts("done.\n");
        {
                struct bi_record *rec;
-               unsigned long initrd_loc;
+               unsigned long initrd_loc = 0;
                unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
                                (1 << 20) - 1, (1 << 20));
                rec = (struct bi_record *)rec_loc;
index 8a1c663..efde532 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/mpc52xx.h>
 #include <asm/mpc52xx_psc.h>
 #include <asm/serial.h>
+#include <asm/io.h>
 #include <asm/time.h>
 
 #if MPC52xx_PF_CONSOLE_PORT == 0
index f6629a2..8861222 100644 (file)
@@ -96,7 +96,7 @@ void write_bugboot_header(int32_t out_fd, uint32_t boot_size)
   uint8_t header_block[HEADER_SIZE];
   bug_boot_header_t *bbh = (bug_boot_header_t *)&header_block[0];
 
-  bzero(header_block, HEADER_SIZE);
+  memset(header_block, 0, HEADER_SIZE);
 
   /* Fill in the PPCBUG ROM boot header */
   strncpy(bbh->magic_word, "BOOT", 4);         /* PPCBUG magic word */
index aba7bd8..c1934f8 100644 (file)
@@ -295,25 +295,27 @@ CONFIG_SOUND_GAMEPORT=y
 # Macintosh device drivers
 #
 
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+# CONFIG_SERIAL_CPM_ALT_SMC2 is not set
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # I2C support
@@ -478,10 +480,6 @@ CONFIG_SCC1_ENET=y
 # CONFIG_SCC3_ENET is not set
 # CONFIG_FEC_ENET is not set
 CONFIG_ENET_BIG_BUFFERS=y
-CONFIG_SMC2_UART=y
-# CONFIG_ALTSMC2 is not set
-# CONFIG_CONS_SMC2 is not set
-# CONFIG_USE_SCC_IO is not set
 
 #
 # Generic MPC8xx Options
index 3f5eb23..66bbefe 100644 (file)
@@ -319,25 +319,26 @@ CONFIG_SOUND_GAMEPORT=y
 # Macintosh device drivers
 #
 
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+# CONFIG_SERIAL_CPM_SMC2 is not set
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # I2C support
@@ -507,8 +508,6 @@ CONFIG_FEC_LXT970=y
 CONFIG_FEC_LXT971=y
 CONFIG_FEC_QS6612=y
 CONFIG_ENET_BIG_BUFFERS=y
-# CONFIG_SMC2_UART is not set
-# CONFIG_USE_SCC_IO is not set
 
 #
 # Generic MPC8xx Options
index 9553f56..021884b 100644 (file)
@@ -92,7 +92,8 @@ CONFIG_KERNEL_ELF=y
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyCPM1"
 
 #
 # Advanced setup
@@ -296,25 +297,27 @@ CONFIG_SOUND_GAMEPORT=y
 # Macintosh device drivers
 #
 
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_SERIAL_CPM_ALT_SMC2=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # I2C support
@@ -479,10 +482,6 @@ CONFIG_SCC_ENET=y
 CONFIG_SCC3_ENET=y
 # CONFIG_FEC_ENET is not set
 CONFIG_ENET_BIG_BUFFERS=y
-CONFIG_SMC2_UART=y
-CONFIG_ALTSMC2=y
-CONFIG_CONS_SMC2=y
-# CONFIG_USE_SCC_IO is not set
 
 #
 # Generic MPC8xx Options
index bc3458b..ba60fea 100644 (file)
@@ -295,25 +295,27 @@ CONFIG_SOUND_GAMEPORT=y
 # Macintosh device drivers
 #
 
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+# CONFIG_SERIAL_CPM_SMC2 is not set
+CONFIG_SERIAL_CPM_ALT_SMC2=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # I2C support
@@ -478,10 +480,6 @@ CONFIG_SCC2_ENET=y
 # CONFIG_SCC3_ENET is not set
 # CONFIG_FEC_ENET is not set
 CONFIG_ENET_BIG_BUFFERS=y
-CONFIG_SMC2_UART=y
-CONFIG_ALTSMC2=y
-# CONFIG_CONS_SMC2 is not set
-# CONFIG_USE_SCC_IO is not set
 
 #
 # Generic MPC8xx Options
index 073a99a..3b44f3d 100644 (file)
@@ -296,25 +296,27 @@ CONFIG_SOUND_GAMEPORT=y
 # Macintosh device drivers
 #
 
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_SERIAL_CPM_ALT_SMC2=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # I2C support
@@ -479,10 +481,6 @@ CONFIG_SCC2_ENET=y
 # CONFIG_SCC3_ENET is not set
 # CONFIG_FEC_ENET is not set
 CONFIG_ENET_BIG_BUFFERS=y
-CONFIG_SMC2_UART=y
-CONFIG_ALTSMC2=y
-# CONFIG_CONS_SMC2 is not set
-# CONFIG_USE_SCC_IO is not set
 
 #
 # Generic MPC8xx Options
index 5aec1d8..b02d196 100644 (file)
@@ -296,25 +296,27 @@ CONFIG_SOUND_GAMEPORT=y
 # Macintosh device drivers
 #
 
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_SERIAL_CPM_ALT_SMC2=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # I2C support
@@ -479,10 +481,6 @@ CONFIG_SCC2_ENET=y
 # CONFIG_SCC3_ENET is not set
 # CONFIG_FEC_ENET is not set
 CONFIG_ENET_BIG_BUFFERS=y
-CONFIG_SMC2_UART=y
-CONFIG_ALTSMC2=y
-# CONFIG_CONS_SMC2 is not set
-# CONFIG_USE_SCC_IO is not set
 
 #
 # Generic MPC8xx Options
index 469fcb4..857e4ab 100644 (file)
@@ -320,25 +320,26 @@ CONFIG_SOUND_GAMEPORT=y
 # Macintosh device drivers
 #
 
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # I2C support
@@ -508,10 +509,6 @@ CONFIG_SCC1_ENET=y
 # CONFIG_SCC3_ENET is not set
 # CONFIG_FEC_ENET is not set
 CONFIG_ENET_BIG_BUFFERS=y
-CONFIG_SMC2_UART=y
-# CONFIG_ALTSMC2 is not set
-# CONFIG_CONS_SMC2 is not set
-# CONFIG_USE_SCC_IO is not set
 
 #
 # Generic MPC8xx Options
index 227fd15..ce9f9f7 100644 (file)
@@ -292,25 +292,26 @@ CONFIG_SOUND_GAMEPORT=y
 # Macintosh device drivers
 #
 
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # I2C support
@@ -476,10 +477,6 @@ CONFIG_SCC2_ENET=y
 # CONFIG_SCC3_ENET is not set
 # CONFIG_FEC_ENET is not set
 # CONFIG_ENET_BIG_BUFFERS is not set
-CONFIG_SMC2_UART=y
-# CONFIG_ALTSMC2 is not set
-# CONFIG_CONS_SMC2 is not set
-# CONFIG_USE_SCC_IO is not set
 
 #
 # Generic MPC8xx Options
index 213e69d..52c3799 100644 (file)
@@ -289,24 +289,26 @@ CONFIG_SOUND_GAMEPORT=y
 # Macintosh device drivers
 #
 
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+CONFIG_SERIAL_CPM_SCC2=y
+CONFIG_SERIAL_CPM_SCC3=y
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # I2C support
@@ -470,10 +472,6 @@ CONFIG_SCC1_ENET=y
 # CONFIG_SCC3_ENET is not set
 # CONFIG_FEC_ENET is not set
 CONFIG_ENET_BIG_BUFFERS=y
-CONFIG_SMC2_UART=y
-# CONFIG_ALTSMC2 is not set
-# CONFIG_CONS_SMC2 is not set
-CONFIG_USE_SCC_IO=y
 
 #
 # Generic MPC8xx Options
index be45380..cf932f1 100644 (file)
@@ -1,26 +1,49 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1
+# Mon Nov  1 16:41:04 2004
 #
 CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=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_LOCALVERSION=""
+# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
-CONFIG_FUTEX=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 is not set
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_TINY_SHMEM=y
 
 #
 # Loadable module support
@@ -28,21 +51,23 @@ CONFIG_FUTEX=y
 # CONFIG_MODULES is not set
 
 #
-# Platform support
+# Processor
 #
-CONFIG_PPC=y
-CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_40x is not set
+# CONFIG_44x is not set
 # CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
 CONFIG_8xx=y
+# CONFIG_E500 is not set
+CONFIG_MATH_EMULATION=y
+# CONFIG_CPU_FREQ is not set
+CONFIG_EMBEDDEDBOOT=y
+CONFIG_NOT_COHERENT_CACHE=y
 
 #
-# IBM 4xx options
+# Platform options
 #
-CONFIG_EMBEDDEDBOOT=y
-CONFIG_SERIAL_CONSOLE=y
-CONFIG_NOT_COHERENT_CACHE=y
 # CONFIG_RPXLITE is not set
 CONFIG_RPXCLASSIC=y
 # CONFIG_BSEIP is not set
@@ -66,27 +91,17 @@ CONFIG_RPXCLASSIC=y
 # CONFIG_WINCEPT is not set
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
-CONFIG_MATH_EMULATION=y
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
 # CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PCI_QSPAN is not set
-CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
-# Parallel port support
+# Bus options
 #
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_QSPAN is not set
 
 #
 # Advanced setup
@@ -100,51 +115,88 @@ CONFIG_HIGHMEM_START=0xfe000000
 CONFIG_LOWMEM_SIZE=0x30000000
 CONFIG_KERNEL_START=0xc0000000
 CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
 CONFIG_BOOT_LOAD=0x00400000
 
+#
+# 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
 #
-# CONFIG_PNP is not set
 
 #
 # 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=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
-# Multi-device support (RAID and LVM)
+# IO Schedulers
 #
-# CONFIG_MD is not set
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
 
 #
-# SCSI support
+# 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
 #
 
+#
+# Macintosh device drivers
+#
+
 #
 # Networking support
 #
@@ -156,66 +208,70 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 # CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER 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_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_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
+# 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_XFRM_USER is not set
+# CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
 # CONFIG_DECNET is not set
-# CONFIG_BRIDGE 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
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
+# CONFIG_MII is not set
 # CONFIG_OAKNET is not set
 
 #
@@ -225,48 +281,34 @@ CONFIG_MII=y
 #
 # Ethernet (10000 Mbit)
 #
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Token Ring devices
 #
-# CONFIG_NET_RADIO is not set
 
 #
-# Token Ring devices (depends on LLC=y)
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_SHAPER is not set
+# CONFIG_NET_RADIO is not set
 
 #
 # Wan interfaces
 #
 # CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA 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_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
+# CONFIG_ISDN is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Telephony Support
 #
-# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -283,54 +325,38 @@ CONFIG_MII=y
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
 
 #
 # Input Device Drivers
 #
 
-#
-# Macintosh device drivers
-#
-
 #
 # 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_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+CONFIG_SERIAL_CPM_SCC2=y
+CONFIG_SERIAL_CPM_SCC3=y
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # IPMI
@@ -346,16 +372,27 @@ CONFIG_GEN_RTC=y
 # CONFIG_GEN_RTC_X 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
-# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
 
 #
 # Multimedia devices
@@ -367,6 +404,27 @@ CONFIG_GEN_RTC=y
 #
 # CONFIG_DVB is not set
 
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
 #
 # File systems
 #
@@ -385,6 +443,7 @@ CONFIG_FS_MBCACHE=y
 # 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
 
@@ -397,17 +456,22 @@ CONFIG_FS_MBCACHE=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# 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=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
 #
@@ -416,6 +480,7 @@ CONFIG_RAMFS=y
 # 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
@@ -432,17 +497,18 @@ CONFIG_RAMFS=y
 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_SUNRPC_GSS is not set
+# 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_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -456,16 +522,15 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_MAC_PARTITION is not set
 # CONFIG_MSDOS_PARTITION is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_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
 
 #
-# Sound
+# Native Language Support
 #
-# CONFIG_SOUND is not set
+# CONFIG_NLS is not set
 
 #
 # MPC8xx CPM Options
@@ -477,42 +542,38 @@ CONFIG_SCC1_ENET=y
 CONFIG_FEC_ENET=y
 # CONFIG_USE_MDIO is not set
 CONFIG_ENET_BIG_BUFFERS=y
-CONFIG_SMC2_UART=y
-# CONFIG_ALTSMC2 is not set
-# CONFIG_CONS_SMC2 is not set
-CONFIG_USE_SCC_IO=y
 
 #
 # Generic MPC8xx Options
 #
 CONFIG_8xx_COPYBACK=y
 # CONFIG_8xx_CPU6 is not set
-# CONFIG_UCODE_PATCH is not set
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
+CONFIG_NO_UCODE_PATCH=y
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
 
 #
-# Library routines
+# Profiling support
 #
-# CONFIG_CRC32 is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index 06e818a..828dd6e 100644 (file)
@@ -1,26 +1,49 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1
+# Mon Nov  1 16:41:09 2004
 #
 CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=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_LOCALVERSION=""
+# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
-CONFIG_FUTEX=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 is not set
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_TINY_SHMEM=y
 
 #
 # Loadable module support
@@ -28,21 +51,23 @@ CONFIG_FUTEX=y
 # CONFIG_MODULES is not set
 
 #
-# Platform support
+# Processor
 #
-CONFIG_PPC=y
-CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_40x is not set
+# CONFIG_44x is not set
 # CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
 CONFIG_8xx=y
+# CONFIG_E500 is not set
+CONFIG_MATH_EMULATION=y
+# CONFIG_CPU_FREQ is not set
+CONFIG_EMBEDDEDBOOT=y
+CONFIG_NOT_COHERENT_CACHE=y
 
 #
-# IBM 4xx options
+# Platform options
 #
-CONFIG_EMBEDDEDBOOT=y
-CONFIG_SERIAL_CONSOLE=y
-CONFIG_NOT_COHERENT_CACHE=y
 CONFIG_RPXLITE=y
 # CONFIG_RPXCLASSIC is not set
 # CONFIG_BSEIP is not set
@@ -66,27 +91,17 @@ CONFIG_RPXLITE=y
 # CONFIG_WINCEPT is not set
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
-CONFIG_MATH_EMULATION=y
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
 # CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PCI_QSPAN is not set
-CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
-# Parallel port support
+# Bus options
 #
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_QSPAN is not set
 
 #
 # Advanced setup
@@ -100,51 +115,88 @@ CONFIG_HIGHMEM_START=0xfe000000
 CONFIG_LOWMEM_SIZE=0x30000000
 CONFIG_KERNEL_START=0xc0000000
 CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
 CONFIG_BOOT_LOAD=0x00400000
 
+#
+# 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
 #
-# CONFIG_PNP is not set
 
 #
 # 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=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
 
 #
-# Multi-device support (RAID and LVM)
+# IO Schedulers
 #
-# CONFIG_MD is not set
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 
 #
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
 
 #
-# SCSI support
+# 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
 #
 
+#
+# Macintosh device drivers
+#
+
 #
 # Networking support
 #
@@ -156,60 +208,64 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 # CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER 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_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_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
+# 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_XFRM_USER is not set
+# CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
 # CONFIG_DECNET is not set
-# CONFIG_BRIDGE 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
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -225,48 +281,34 @@ CONFIG_NET_ETHERNET=y
 #
 # Ethernet (10000 Mbit)
 #
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Token Ring devices
 #
-# CONFIG_NET_RADIO is not set
 
 #
-# Token Ring devices (depends on LLC=y)
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_SHAPER is not set
+# CONFIG_NET_RADIO is not set
 
 #
 # Wan interfaces
 #
 # CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA 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_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
+# CONFIG_ISDN is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Telephony Support
 #
-# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -283,54 +325,38 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
 
 #
 # Input Device Drivers
 #
 
-#
-# Macintosh device drivers
-#
-
 #
 # 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_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+# CONFIG_SERIAL_CPM_SMC2 is not set
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # IPMI
@@ -346,16 +372,27 @@ CONFIG_GEN_RTC=y
 # CONFIG_GEN_RTC_X 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
-# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
 
 #
 # Multimedia devices
@@ -367,6 +404,27 @@ CONFIG_GEN_RTC=y
 #
 # CONFIG_DVB is not set
 
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
 #
 # File systems
 #
@@ -385,6 +443,7 @@ CONFIG_FS_MBCACHE=y
 # 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
 
@@ -397,17 +456,22 @@ CONFIG_FS_MBCACHE=y
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# 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=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
 #
@@ -416,6 +480,7 @@ CONFIG_RAMFS=y
 # 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
@@ -432,17 +497,18 @@ CONFIG_RAMFS=y
 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_SUNRPC_GSS is not set
+# 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_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -456,16 +522,15 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_MAC_PARTITION is not set
 # CONFIG_MSDOS_PARTITION is not set
 # CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_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
 
 #
-# Sound
+# Native Language Support
 #
-# CONFIG_SOUND is not set
+# CONFIG_NLS is not set
 
 #
 # MPC8xx CPM Options
@@ -476,40 +541,38 @@ CONFIG_SCC2_ENET=y
 # CONFIG_SCC3_ENET is not set
 # CONFIG_FEC_ENET is not set
 # CONFIG_ENET_BIG_BUFFERS is not set
-# CONFIG_SMC2_UART is not set
-# CONFIG_USE_SCC_IO is not set
 
 #
 # Generic MPC8xx Options
 #
 CONFIG_8xx_COPYBACK=y
 # CONFIG_8xx_CPU6 is not set
-# CONFIG_UCODE_PATCH is not set
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
+CONFIG_NO_UCODE_PATCH=y
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
 
 #
-# Library routines
+# Profiling support
 #
-# CONFIG_CRC32 is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
index c00bad6..7f53d19 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 #include <linux/kernel.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 
 /*
  * If the bitops are not inlined in bitops.h, they are defined here.
index cfcd6e1..8b57c3e 100644 (file)
 #include <asm/ppc_asm.h>
 #include <asm/offsets.h>
 
+/* Macro to make the code more readable. */
+#ifdef CONFIG_8xx_CPU6
+#define DO_8xx_CPU6(val, reg)  \
+       li      reg, val;       \
+       stw     reg, 12(r0);    \
+       lwz     reg, 12(r0);
+#else
+#define DO_8xx_CPU6(val, reg)
+#endif
        .text
        .globl  _stext
 _stext:
-
-/*
- * _start is defined this way because the XCOFF loader in the OpenFirmware
- * on the powermac expects the entry point to be a procedure descriptor.
- */
        .text
        .globl  _start
 _start:
@@ -77,7 +81,6 @@ _start:
  * and the CCR at memory location 0.....Someday I'll fix this.....
  *     -- Dan
  */
-
        .globl  __start
 __start:
        mr      r31,r3                  /* save parameters */
@@ -85,7 +88,6 @@ __start:
        mr      r29,r5
        mr      r28,r6
        mr      r27,r7
-       li      r24,0                   /* cpu # */
 
        /* We have to turn on the MMU right away so we get cache modes
         * set correctly.
@@ -113,63 +115,106 @@ turn_on_mmu:
  * task's thread_struct.
  */
 #define EXCEPTION_PROLOG       \
-       mtspr   SPRG0,r20;      \
-       mtspr   SPRG1,r21;      \
-       mfcr    r20;            \
-       mfspr   r21,SPRG2;              /* exception stack to use from */ \
-       cmpwi   0,r21,0;                /* user mode or RTAS */ \
-       bne     1f;             \
-       tophys(r21,r1);                 /* use tophys(kernel sp) otherwise */ \
-       subi    r21,r21,INT_FRAME_SIZE; /* alloc exc. frame */\
-1:     stw     r20,_CCR(r21);          /* save registers */ \
-       stw     r22,GPR22(r21); \
-       stw     r23,GPR23(r21); \
-       mfspr   r20,SPRG0;      \
-       stw     r20,GPR20(r21); \
-       mfspr   r22,SPRG1;      \
-       stw     r22,GPR21(r21); \
-       mflr    r20;            \
-       stw     r20,_LINK(r21); \
-       mfctr   r22;            \
-       stw     r22,_CTR(r21);  \
-       mfspr   r20,XER;        \
-       stw     r20,_XER(r21);  \
-       mfspr   r22,SRR0;       \
-       mfspr   r23,SRR1;       \
-       stw     r0,GPR0(r21);   \
-       stw     r1,GPR1(r21);   \
-       stw     r2,GPR2(r21);   \
-       stw     r1,0(r21);      \
-       tovirt(r1,r21);                 /* set new kernel sp */ \
-       SAVE_4GPRS(3, r21);     \
-       SAVE_GPR(7, r21);
+       mtspr   SPRG0,r10;      \
+       mtspr   SPRG1,r11;      \
+       mfcr    r10;            \
+       EXCEPTION_PROLOG_1;     \
+       EXCEPTION_PROLOG_2
+
+#define EXCEPTION_PROLOG_1     \
+       mfspr   r11,SRR1;               /* check whether user or kernel */ \
+       andi.   r11,r11,MSR_PR; \
+       tophys(r11,r1);                 /* use tophys(r1) if kernel */ \
+       beq     1f;             \
+       mfspr   r11,SPRG3;      \
+       lwz     r11,THREAD_INFO-THREAD(r11);    \
+       addi    r11,r11,THREAD_SIZE;    \
+       tophys(r11,r11);        \
+1:     subi    r11,r11,INT_FRAME_SIZE  /* alloc exc. frame */
+
+
+#define EXCEPTION_PROLOG_2     \
+       CLR_TOP32(r11);         \
+       stw     r10,_CCR(r11);          /* save 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   r12,SRR0;       \
+       mfspr   r9,SRR1;        \
+       stw     r1,GPR1(r11);   \
+       stw     r1,0(r11);      \
+       tovirt(r1,r11);                 /* set new kernel sp */ \
+       li      r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \
+       MTMSRD(r10);                    /* (except for mach check in rtas) */ \
+       stw     r0,GPR0(r11);   \
+       SAVE_4GPRS(3, r11);     \
+       SAVE_2GPRS(7, r11)
+
 /*
  * Note: code which follows this uses cr0.eq (set if from kernel),
- * r21, r22 (SRR0), and r23 (SRR1).
+ * r11, r12 (SRR0), and r9 (SRR1).
+ *
+ * Note2: once we have set r1 we are in a position to take exceptions
+ * again, and we could thus set MSR:RI at that point.
  */
 
 /*
  * Exception vectors.
  */
-#define STD_EXCEPTION(n, label, hdlr)          \
+#define EXCEPTION(n, label, hdlr, xfer)                \
        . = n;                                  \
 label:                                         \
        EXCEPTION_PROLOG;                       \
        addi    r3,r1,STACK_FRAME_OVERHEAD;     \
-       li      r20,MSR_KERNEL;                 \
-       bl      transfer_to_handler;            \
-       .long   hdlr;                           \
-       .long   ret_from_except
+       xfer(n, hdlr)
+
+#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret)    \
+       li      r10,trap;                                       \
+       stw     r10,TRAP(r11);                                  \
+       li      r10,MSR_KERNEL;                                 \
+       copyee(r10, r9);                                        \
+       bl      tfer;                                           \
+i##n:                                                          \
+       .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(n, hdlr, n, NOCOPY, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define EXC_XFER_LITE(n, hdlr)         \
+       EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
+                         ret_from_except)
+
+#define EXC_XFER_EE(n, hdlr)           \
+       EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define EXC_XFER_EE_LITE(n, hdlr)      \
+       EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \
+                         ret_from_except)
 
 /* System reset */
-#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */
-       STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
-#else
-       STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif
+       EXCEPTION(0x100, Reset, UnknownException, EXC_XFER_STD)
 
 /* Machine check */
-       STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+       . = 0x200
+MachineCheck:
+       EXCEPTION_PROLOG
+       mfspr r4,DAR
+       stw r4,_DAR(r11)
+       mfspr r5,DSISR
+       stw r5,_DSISR(r11)
+       addi r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_STD(0x200, MachineCheckException)
 
 /* Data access exception.
  * This is "never generated" by the MPC8xx.  We jump to it for other
@@ -178,17 +223,11 @@ label:                                            \
        . = 0x300
 DataAccess:
        EXCEPTION_PROLOG
-       mfspr   r20,DSISR
-       stw     r20,_DSISR(r21)
-       mr      r5,r20
+       mfspr   r10,DSISR
+       stw     r10,_DSISR(r11)
+       mr      r5,r10
        mfspr   r4,DAR
-       stw     r4,_DAR(r21)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       li      r20,MSR_KERNEL
-       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
-       bl      transfer_to_handler
-       .long   do_page_fault
-       .long   ret_from_except
+       EXC_XFER_EE_LITE(0x300, handle_page_fault)
 
 /* Instruction access exception.
  * This is "never generated" by the MPC8xx.  We jump to it for other
@@ -197,94 +236,52 @@ DataAccess:
        . = 0x400
 InstructionAccess:
        EXCEPTION_PROLOG
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       mr      r4,r22
-       mr      r5,r23
-       li      r20,MSR_KERNEL
-       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
-       bl      transfer_to_handler
-       .long   do_page_fault
-       .long   ret_from_except
+       mr      r4,r12
+       mr      r5,r9
+       EXC_XFER_EE_LITE(0x400, handle_page_fault)
 
 /* External interrupt */
-       . = 0x500;
-HardwareInterrupt:
-       EXCEPTION_PROLOG;
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       li      r20,MSR_KERNEL
-       li      r4,0
-       bl      transfer_to_handler
-       .globl do_IRQ_intercept
-do_IRQ_intercept:
-       .long   do_IRQ;
-       .long   ret_from_intercept
-
+       EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
 
 /* Alignment exception */
        . = 0x600
 Alignment:
        EXCEPTION_PROLOG
        mfspr   r4,DAR
-       stw     r4,_DAR(r21)
+       stw     r4,_DAR(r11)
        mfspr   r5,DSISR
-       stw     r5,_DSISR(r21)
+       stw     r5,_DSISR(r11)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       li      r20,MSR_KERNEL
-       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
-       bl      transfer_to_handler
-       .long   AlignmentException
-       .long   ret_from_except
+       EXC_XFER_EE(0x600, AlignmentException)
 
 /* Program check exception */
-       . = 0x700
-ProgramCheck:
-       EXCEPTION_PROLOG
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       li      r20,MSR_KERNEL
-       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
-       bl      transfer_to_handler
-       .long   ProgramCheckException
-       .long   ret_from_except
+       EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD)
 
 /* No FPU on MPC8xx.  This exception is not supposed to happen.
 */
-       STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+       EXCEPTION(0x800, FPUnavailable, UnknownException, EXC_XFER_STD)
 
-       . = 0x900
-Decrementer:
-       EXCEPTION_PROLOG
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       li      r20,MSR_KERNEL
-       bl      transfer_to_handler
-       .globl timer_interrupt_intercept
-timer_interrupt_intercept:
-       .long   timer_interrupt
-       .long   ret_from_intercept
+/* Decrementer */
+       EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
 
-       STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
-       STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+       EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE)
 
 /* System call */
        . = 0xc00
 SystemCall:
        EXCEPTION_PROLOG
-       stw     r3,ORIG_GPR3(r21)
-       li      r20,MSR_KERNEL
-       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
-       bl      transfer_to_handler
-       .long   DoSyscall
-       .long   ret_from_except
+       EXC_XFER_EE_LITE(0xc00, DoSyscall)
 
 /* Single step - not used on 601 */
-       STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
-
-       STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
-       STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+       EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD)
+       EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0xf00, Trap_0f, UnknownException, EXC_XFER_EE)
 
 /* On the MPC8xx, this is a software emulation interrupt.  It occurs
  * for all unimplemented and illegal instructions.
  */
-       STD_EXCEPTION(0x1000, SoftEmu, SoftwareEmulation)
+       EXCEPTION(0x1000, SoftEmu, SoftwareEmulation, EXC_XFER_STD)
 
        . = 0x1100
 /*
@@ -302,58 +299,43 @@ SystemCall:
 InstructionTLBMiss:
 #ifdef CONFIG_8xx_CPU6
        stw     r3, 8(r0)
-       li      r3, 0x3f80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   M_TW, r20       /* Save a couple of working registers */
-       mfcr    r20
-       stw     r20, 0(r0)
-       stw     r21, 4(r0)
-       mfspr   r20, SRR0       /* Get effective address of fault */
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x3780
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
 #endif
-       mtspr   MD_EPN, r20     /* Have to use MD_EPN for walk, MI_EPN can't */
-       mfspr   r20, M_TWB      /* Get level 1 table entry address */
+       DO_8xx_CPU6(0x3f80, r3)
+       mtspr   M_TW, r10       /* Save a couple of working registers */
+       mfcr    r10
+       stw     r10, 0(r0)
+       stw     r11, 4(r0)
+       mfspr   r10, SRR0       /* Get effective address of fault */
+       DO_8xx_CPU6(0x3780, r3)
+       mtspr   MD_EPN, r10     /* Have to use MD_EPN for walk, MI_EPN can't */
+       mfspr   r10, M_TWB      /* Get level 1 table entry address */
 
        /* If we are faulting a kernel address, we have to use the
         * kernel page tables.
         */
-       andi.   r21, r20, 0x0800        /* Address >= 0x80000000 */
+       andi.   r11, r10, 0x0800        /* Address >= 0x80000000 */
        beq     3f
-       lis     r21, swapper_pg_dir@h
-       ori     r21, r21, swapper_pg_dir@l
-       rlwimi  r20, r21, 0, 2, 19
+       lis     r11, swapper_pg_dir@h
+       ori     r11, r11, swapper_pg_dir@l
+       rlwimi  r10, r11, 0, 2, 19
 3:
-       lwz     r21, 0(r20)     /* Get the level 1 entry */
-       rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */
+       lwz     r11, 0(r10)     /* Get the level 1 entry */
+       rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
        beq     2f              /* If zero, don't try to find a pte */
 
        /* We have a pte table, so load the MI_TWC with the attributes
         * for this "segment."
         */
-       tophys(r21,r21)
-       ori     r21,r21,1               /* Set valid bit */
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x2b80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   MI_TWC, r21     /* Set segment attributes */
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x3b80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   MD_TWC, r21     /* Load pte table base address */
-       mfspr   r21, MD_TWC     /* ....and get the pte address */
-       lwz     r20, 0(r21)     /* Get the pte */
+       ori     r11,r11,1               /* Set valid bit */
+       DO_8xx_CPU6(0x2b80, r3)
+       mtspr   MI_TWC, r11     /* Set segment attributes */
+       DO_8xx_CPU6(0x3b80, r3)
+       mtspr   MD_TWC, r11     /* Load pte table base address */
+       mfspr   r11, MD_TWC     /* ....and get the pte address */
+       lwz     r10, 0(r11)     /* Get the pte */
 
-       ori     r20, r20, _PAGE_ACCESSED
-       stw     r20, 0(r21)
+       ori     r10, r10, _PAGE_ACCESSED
+       stw     r10, 0(r11)
 
        /* The Linux PTE won't go exactly into the MMU TLB.
         * Software indicator bits 21, 22 and 28 must be clear.
@@ -361,29 +343,24 @@ InstructionTLBMiss:
         * set.  All other Linux PTE bits control the behavior
         * of the MMU.
         */
-       li      r21, 0x00f0
-       rlwimi  r20, r21, 0, 24, 28     /* Set 24-27, clear 28 */
-
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x2d80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   MI_RPN, r20     /* Update TLB entry */
-
-       mfspr   r20, M_TW       /* Restore registers */
-       lwz     r21, 0(r0)
-       mtcr    r21
-       lwz     r21, 4(r0)
+       li      r11, 0x00f0
+       rlwimi  r10, r11, 0, 24, 28     /* Set 24-27, clear 28 */
+       DO_8xx_CPU6(0x2d80, r3)
+       mtspr   MI_RPN, r10     /* Update TLB entry */
+
+       mfspr   r10, M_TW       /* Restore registers */
+       lwz     r11, 0(r0)
+       mtcr    r11
+       lwz     r11, 4(r0)
 #ifdef CONFIG_8xx_CPU6
        lwz     r3, 8(r0)
 #endif
        rfi
 
-2:     mfspr   r20, M_TW       /* Restore registers */
-       lwz     r21, 0(r0)
-       mtcr    r21
-       lwz     r21, 4(r0)
+2:     mfspr   r10, M_TW       /* Restore registers */
+       lwz     r11, 0(r0)
+       mtcr    r11
+       lwz     r11, 4(r0)
 #ifdef CONFIG_8xx_CPU6
        lwz     r3, 8(r0)
 #endif
@@ -393,41 +370,34 @@ InstructionTLBMiss:
 DataStoreTLBMiss:
 #ifdef CONFIG_8xx_CPU6
        stw     r3, 8(r0)
-       li      r3, 0x3f80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
 #endif
-       mtspr   M_TW, r20       /* Save a couple of working registers */
-       mfcr    r20
-       stw     r20, 0(r0)
-       stw     r21, 4(r0)
-       mfspr   r20, M_TWB      /* Get level 1 table entry address */
+       DO_8xx_CPU6(0x3f80, r3)
+       mtspr   M_TW, r10       /* Save a couple of working registers */
+       mfcr    r10
+       stw     r10, 0(r0)
+       stw     r11, 4(r0)
+       mfspr   r10, M_TWB      /* Get level 1 table entry address */
 
        /* If we are faulting a kernel address, we have to use the
         * kernel page tables.
         */
-       andi.   r21, r20, 0x0800
+       andi.   r11, r10, 0x0800
        beq     3f
-       lis     r21, swapper_pg_dir@h
-       ori     r21, r21, swapper_pg_dir@l
-       rlwimi r20, r21, 0, 2, 19
+       lis     r11, swapper_pg_dir@h
+       ori     r11, r11, swapper_pg_dir@l
+       rlwimi  r10, r11, 0, 2, 19
 3:
-       lwz     r21, 0(r20)     /* Get the level 1 entry */
-       rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */
+       lwz     r11, 0(r10)     /* Get the level 1 entry */
+       rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
        beq     2f              /* If zero, don't try to find a pte */
 
        /* We have a pte table, so load fetch the pte from the table.
         */
-       tophys(r21, r21)
-       ori     r21, r21, 1     /* Set valid bit in physical L2 page */
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x3b80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   MD_TWC, r21     /* Load pte table base address */
-       mfspr   r20, MD_TWC     /* ....and get the pte address */
-       lwz     r20, 0(r20)     /* Get the pte */
+       ori     r11, r11, 1     /* Set valid bit in physical L2 page */
+       DO_8xx_CPU6(0x3b80, r3)
+       mtspr   MD_TWC, r11     /* Load pte table base address */
+       mfspr   r10, MD_TWC     /* ....and get the pte address */
+       lwz     r10, 0(r10)     /* Get the pte */
 
        /* Insert the Guarded flag into the TWC from the Linux PTE.
         * It is bit 27 of both the Linux PTE and the TWC (at least
@@ -435,17 +405,13 @@ DataStoreTLBMiss:
         * this into the Linux pgd/pmd and load it in the operation
         * above.
         */
-       rlwimi  r21, r20, 0, 27, 27
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x3b80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   MD_TWC, r21
+       rlwimi  r11, r10, 0, 27, 27
+       DO_8xx_CPU6(0x3b80, r3)
+       mtspr   MD_TWC, r11
 
-       mfspr   r21, MD_TWC     /* get the pte address again */
-       ori     r20, r20, _PAGE_ACCESSED
-       stw     r20, 0(r21)
+       mfspr   r11, MD_TWC     /* get the pte address again */
+       ori     r10, r10, _PAGE_ACCESSED
+       stw     r10, 0(r11)
 
        /* The Linux PTE won't go exactly into the MMU TLB.
         * Software indicator bits 21, 22 and 28 must be clear.
@@ -453,29 +419,24 @@ DataStoreTLBMiss:
         * set.  All other Linux PTE bits control the behavior
         * of the MMU.
         */
-       li      r21, 0x00f0
-       rlwimi  r20, r21, 0, 24, 28     /* Set 24-27, clear 28 */
-
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x3d80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   MD_RPN, r20     /* Update TLB entry */
-
-       mfspr   r20, M_TW       /* Restore registers */
-       lwz     r21, 0(r0)
-       mtcr    r21
-       lwz     r21, 4(r0)
+       li      r11, 0x00f0
+       rlwimi  r10, r11, 0, 24, 28     /* Set 24-27, clear 28 */
+       DO_8xx_CPU6(0x3d80, r3)
+       mtspr   MD_RPN, r10     /* Update TLB entry */
+
+       mfspr   r10, M_TW       /* Restore registers */
+       lwz     r11, 0(r0)
+       mtcr    r11
+       lwz     r11, 4(r0)
 #ifdef CONFIG_8xx_CPU6
        lwz     r3, 8(r0)
 #endif
        rfi
 
-2:     mfspr   r20, M_TW       /* Restore registers */
-       lwz     r21, 0(r0)
-       mtcr    r21
-       lwz     r21, 4(r0)
+2:     mfspr   r10, M_TW       /* Restore registers */
+       lwz     r11, 0(r0)
+       mtcr    r11
+       lwz     r11, 4(r0)
 #ifdef CONFIG_8xx_CPU6
        lwz     r3, 8(r0)
 #endif
@@ -501,19 +462,17 @@ InstructionTLBError:
 DataTLBError:
 #ifdef CONFIG_8xx_CPU6
        stw     r3, 8(r0)
-       li      r3, 0x3f80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
 #endif
-       mtspr   M_TW, r20       /* Save a couple of working registers */
-       mfcr    r20
-       stw     r20, 0(r0)
-       stw     r21, 4(r0)
+       DO_8xx_CPU6(0x3f80, r3)
+       mtspr   M_TW, r10       /* Save a couple of working registers */
+       mfcr    r10
+       stw     r10, 0(r0)
+       stw     r11, 4(r0)
 
        /* First, make sure this was a store operation.
        */
-       mfspr   r20, DSISR
-       andis.  r21, r20, 0x0200        /* If set, indicates store op */
+       mfspr   r10, DSISR
+       andis.  r11, r10, 0x0200        /* If set, indicates store op */
        beq     2f
 
        /* The EA of a data TLB miss is automatically stored in the MD_EPN
@@ -532,54 +491,45 @@ DataTLBError:
         * are initialized in mapin_ram().  This will avoid the problem,
         * assuming we only use the dcbi instruction on kernel addresses.
         */
-       mfspr   r20, DAR
-       rlwinm  r21, r20, 0, 0, 19
-       ori     r21, r21, MD_EVALID
-       mfspr   r20, M_CASID
-       rlwimi  r21, r20, 0, 28, 31
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x3780
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   MD_EPN, r21
+       mfspr   r10, DAR
+       rlwinm  r11, r10, 0, 0, 19
+       ori     r11, r11, MD_EVALID
+       mfspr   r10, M_CASID
+       rlwimi  r11, r10, 0, 28, 31
+       DO_8xx_CPU6(0x3780, r3)
+       mtspr   MD_EPN, r11
 
-       mfspr   r20, M_TWB      /* Get level 1 table entry address */
+       mfspr   r10, M_TWB      /* Get level 1 table entry address */
 
        /* If we are faulting a kernel address, we have to use the
         * kernel page tables.
         */
-       andi.   r21, r20, 0x0800
+       andi.   r11, r10, 0x0800
        beq     3f
-       lis     r21, swapper_pg_dir@h
-       ori     r21, r21, swapper_pg_dir@l
-       rlwimi  r20, r21, 0, 2, 19
+       lis     r11, swapper_pg_dir@h
+       ori     r11, r11, swapper_pg_dir@l
+       rlwimi  r10, r11, 0, 2, 19
 3:
-       lwz     r21, 0(r20)     /* Get the level 1 entry */
-       rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */
+       lwz     r11, 0(r10)     /* Get the level 1 entry */
+       rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
        beq     2f              /* If zero, bail */
 
        /* We have a pte table, so fetch the pte from the table.
         */
-       tophys(r21, r21)
-       ori     r21, r21, 1             /* Set valid bit in physical L2 page */
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x3b80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   MD_TWC, r21             /* Load pte table base address */
-       mfspr   r21, MD_TWC             /* ....and get the pte address */
-       lwz     r20, 0(r21)             /* Get the pte */
+       ori     r11, r11, 1             /* Set valid bit in physical L2 page */
+       DO_8xx_CPU6(0x3b80, r3)
+       mtspr   MD_TWC, r11             /* Load pte table base address */
+       mfspr   r11, MD_TWC             /* ....and get the pte address */
+       lwz     r10, 0(r11)             /* Get the pte */
 
-       andi.   r21, r20, _PAGE_RW      /* Is it writeable? */
+       andi.   r11, r10, _PAGE_RW      /* Is it writeable? */
        beq     2f                      /* Bail out if not */
 
        /* Update 'changed', among others.
        */
-       ori     r20, r20, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
-       mfspr   r21, MD_TWC             /* Get pte address again */
-       stw     r20, 0(r21)             /* and update pte in table */
+       ori     r10, r10, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
+       mfspr   r11, MD_TWC             /* Get pte address again */
+       stw     r10, 0(r11)             /* and update pte in table */
 
        /* The Linux PTE won't go exactly into the MMU TLB.
         * Software indicator bits 21, 22 and 28 must be clear.
@@ -587,50 +537,45 @@ DataTLBError:
         * set.  All other Linux PTE bits control the behavior
         * of the MMU.
         */
-       li      r21, 0x00f0
-       rlwimi  r20, r21, 0, 24, 28     /* Set 24-27, clear 28 */
-
-#ifdef CONFIG_8xx_CPU6
-       li      r3, 0x3d80
-       stw     r3, 12(r0)
-       lwz     r3, 12(r0)
-#endif
-       mtspr   MD_RPN, r20     /* Update TLB entry */
-
-       mfspr   r20, M_TW       /* Restore registers */
-       lwz     r21, 0(r0)
-       mtcr    r21
-       lwz     r21, 4(r0)
+       li      r11, 0x00f0
+       rlwimi  r10, r11, 0, 24, 28     /* Set 24-27, clear 28 */
+       DO_8xx_CPU6(0x3d80, r3)
+       mtspr   MD_RPN, r10     /* Update TLB entry */
+
+       mfspr   r10, M_TW       /* Restore registers */
+       lwz     r11, 0(r0)
+       mtcr    r11
+       lwz     r11, 4(r0)
 #ifdef CONFIG_8xx_CPU6
        lwz     r3, 8(r0)
 #endif
        rfi
 2:
-       mfspr   r20, M_TW       /* Restore registers */
-       lwz     r21, 0(r0)
-       mtcr    r21
-       lwz     r21, 4(r0)
+       mfspr   r10, M_TW       /* Restore registers */
+       lwz     r11, 0(r0)
+       mtcr    r11
+       lwz     r11, 4(r0)
 #ifdef CONFIG_8xx_CPU6
        lwz     r3, 8(r0)
 #endif
        b       DataAccess
 
-       STD_EXCEPTION(0x1500, Trap_15, UnknownException)
-       STD_EXCEPTION(0x1600, Trap_16, UnknownException)
-       STD_EXCEPTION(0x1700, Trap_17, TAUException)
-       STD_EXCEPTION(0x1800, Trap_18, UnknownException)
-       STD_EXCEPTION(0x1900, Trap_19, UnknownException)
-       STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
-       STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+       EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1700, Trap_17, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE)
 
 /* On the MPC8xx, these next four traps are used for development
  * support of breakpoints and such.  Someday I will get around to
  * using them.
  */
-       STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
-       STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
-       STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
-       STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+       EXCEPTION(0x1c00, Trap_1c, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1d00, Trap_1d, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1e00, Trap_1e, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1f00, Trap_1f, UnknownException, EXC_XFER_EE)
 
        . = 0x2000
 
@@ -638,11 +583,6 @@ DataTLBError:
 giveup_fpu:
        blr
 
-/* Maybe someday.......
-*/
-_GLOBAL(__setup_cpu_8xx)
-       blr
-
 /*
  * This is where the main kernel code starts.
  */
index 6f54039..0c655c1 100644 (file)
@@ -237,4 +237,70 @@ label:
                          ret_from_except)
 
 
+/* Check for a single step debug exception while in an exception
+ * handler before state has been saved.  This is to catch the case
+ * where an instruction that we are trying to single step causes
+ * an exception (eg ITLB/DTLB miss) and thus the first instruction of
+ * the exception handler generates a single step debug exception.
+ *
+ * If we get a debug trap on the first instruction of an exception handler,
+ * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
+ * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
+ * The exception handler was handling a non-critical interrupt, so it will
+ * save (and later restore) the MSR via SPRN_CSRR1, which will still have
+ * the MSR_DE bit set.
+ */
+#define DEBUG_EXCEPTION                                                              \
+       START_EXCEPTION(Debug);                                               \
+       CRITICAL_EXCEPTION_PROLOG;                                            \
+                                                                             \
+       /*                                                                    \
+        * If there is a single step or branch-taken exception in an          \
+        * exception entry sequence, it was probably meant to apply to        \
+        * the code where the exception occurred (since exception entry       \
+        * doesn't turn off DE automatically).  We simulate the effect        \
+        * of turning off DE on entry to an exception handler by turning      \
+        * off DE in the CSRR1 value and clearing the debug status.           \
+        */                                                                   \
+       mfspr   r10,SPRN_DBSR;          /* check single-step/branch taken */  \
+       andis.  r10,r10,DBSR_IC@h;                                            \
+       beq+    2f;                                                           \
+                                                                             \
+       lis     r10,KERNELBASE@h;       /* check if exception in vectors */   \
+       ori     r10,r10,KERNELBASE@l;                                         \
+       cmplw   r12,r10;                                                      \
+       blt+    2f;                     /* addr below exception vectors */    \
+                                                                             \
+       lis     r10,Debug@h;                                                  \
+       ori     r10,r10,Debug@l;                                              \
+       cmplw   r12,r10;                                                      \
+       bgt+    2f;                     /* addr above exception vectors */    \
+                                                                             \
+       /* here it looks like we got an inappropriate debug exception. */     \
+1:     rlwinm  r9,r9,0,~MSR_DE;        /* clear DE in the CSRR1 value */     \
+       lis     r10,DBSR_IC@h;          /* clear the IC event */              \
+       mtspr   SPRN_DBSR,r10;                                                \
+       /* restore state and get out */                                       \
+       lwz     r10,_CCR(r11);                                                \
+       lwz     r0,GPR0(r11);                                                 \
+       lwz     r1,GPR1(r11);                                                 \
+       mtcrf   0x80,r10;                                                     \
+       mtspr   CSRR0,r12;                                                    \
+       mtspr   CSRR1,r9;                                                     \
+       lwz     r9,GPR9(r11);                                                 \
+       lwz     r12,GPR12(r11);                                               \
+       mtspr   SPRG2,r8;               /* SPRG2 only used in criticals */    \
+       lis     r8,crit_save@ha;                                              \
+       lwz     r10,crit_r10@l(r8);                                           \
+       lwz     r11,crit_r11@l(r8);                                           \
+       mfspr   r8,SPRG2;                                                     \
+                                                                             \
+       rfci;                                                                 \
+       b       .;                                                            \
+                                                                             \
+       /* continue normal handling for a critical exception... */            \
+2:     mfspr   r4,SPRN_DBSR;                                                 \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                                   \
+       EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+
 #endif /* __HEAD_BOOKE_H__ */
index cf96419..c671a93 100644 (file)
@@ -668,64 +668,8 @@ interrupt_base:
        /* Performance Monitor */
        EXCEPTION(0x2060, PerformanceMonitor, UnknownException, EXC_XFER_EE)
 
-/* Check for a single step debug exception while in an exception
- * handler before state has been saved.  This is to catch the case
- * where an instruction that we are trying to single step causes
- * an exception (eg ITLB/DTLB miss) and thus the first instruction of
- * the exception handler generates a single step debug exception.
- *
- * If we get a debug trap on the first instruction of an exception handler,
- * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
- * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
- * The exception handler was handling a non-critical interrupt, so it will
- * save (and later restore) the MSR via SPRN_SRR1, which will still have
- * the MSR_DE bit set.
- */
        /* Debug Interrupt */
-       START_EXCEPTION(Debug)
-       CRITICAL_EXCEPTION_PROLOG
-
-       /*
-        * If this is a single step or branch-taken exception in an
-        * exception entry sequence, it was probably meant to apply to
-        * the code where the exception occurred (since exception entry
-        * doesn't turn off DE automatically).  We simulate the effect
-        * of turning off DE on entry to an exception handler by turning
-        * off DE in the CSRR1 value and clearing the debug status.
-        */
-       mfspr   r10,SPRN_DBSR           /* check single-step/branch taken */
-       andis.  r10,r10,(DBSR_IC|DBSR_BT)@h
-       beq+    1f
-       andi.   r0,r9,MSR_PR            /* check supervisor */
-       beq     2f                      /* branch if we need to fix it up... */
-
-       /* continue normal handling for a critical exception... */
-1:     mfspr   r4,SPRN_DBSR
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       EXC_XFER_TEMPLATE(DebugException, 0x2002, \
-               (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
-               NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
-
-       /* here it looks like we got an inappropriate debug exception. */
-2:     rlwinm  r9,r9,0,~MSR_DE         /* clear DE in the CSRR1 value */
-       mtspr   SPRN_DBSR,r10           /* clear the IC/BT debug intr status */
-       /* restore state and get out */
-       lwz     r10,_CCR(r11)
-       lwz     r0,GPR0(r11)
-       lwz     r1,GPR1(r11)
-       mtcrf   0x80,r10
-       mtspr   CSRR0,r12
-       mtspr   CSRR1,r9
-       lwz     r9,GPR9(r11)
-
-       mtspr   SPRG2,r8;               /* SPRG2 only used in criticals */
-       lis     r8,crit_save@ha;
-       lwz     r10,crit_r10@l(r8)
-       lwz     r11,crit_r11@l(r8)
-       mfspr   r8,SPRG2
-
-       rfci
-       b       .
+       DEBUG_EXCEPTION
 
 /*
  * Local functions
index 08cddde..0f1eee3 100644 (file)
@@ -231,14 +231,12 @@ EXPORT_SYMBOL(pcibios_align_resource);
 static void __init
 pcibios_allocate_bus_resources(struct list_head *bus_list)
 {
-       struct list_head *ln;
        struct pci_bus *bus;
        int i;
        struct resource *res, *pr;
 
        /* Depth-First Search on bus tree */
-       for (ln = bus_list->next; ln != bus_list; ln=ln->next) {
-               bus = pci_bus_b(ln);
+       list_for_each_entry(bus, bus_list, node) {
                for (i = 0; i < 4; ++i) {
                        if ((res = bus->resource[i]) == NULL || !res->flags
                            || res->start > res->end)
@@ -381,7 +379,6 @@ probe_resource(struct pci_bus *parent, struct resource *pr,
        struct pci_bus *bus;
        struct pci_dev *dev;
        struct resource *r;
-       struct list_head *ln;
        int i;
 
        for (r = pr->child; r != NULL; r = r->sibling) {
@@ -390,9 +387,7 @@ probe_resource(struct pci_bus *parent, struct resource *pr,
                        return 1;
                }
        }
-       for (ln = parent->children.next; ln != &parent->children;
-            ln = ln->next) {
-               bus = pci_bus_b(ln);
+       list_for_each_entry(bus, &parent->children, node) {
                for (i = 0; i < 4; ++i) {
                        if ((r = bus->resource[i]) == NULL)
                                continue;
@@ -406,8 +401,7 @@ probe_resource(struct pci_bus *parent, struct resource *pr,
                        }
                }
        }
-       for (ln = parent->devices.next; ln != &parent->devices; ln=ln->next) {
-               dev = pci_dev_b(ln);
+       list_for_each_entry(dev, &parent->devices, bus_list) {
                for (i = 0; i < 6; ++i) {
                        r = &dev->resource[i];
                        if (!r->flags || (r->flags & IORESOURCE_UNSET))
@@ -1102,7 +1096,7 @@ do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
 static int __init
 check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga)
 {
-       struct list_head *ln;
+       struct pci_dev *dev;
        int     i;
        int     rc = 0;
 
@@ -1110,8 +1104,7 @@ check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga)
        res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \
     } while (0)
 
-       for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
-               struct pci_dev *dev = pci_dev_b(ln);
+       list_for_each_entry(dev, &bus->devices, bus_list) {
                u16 class = dev->class >> 8;
 
                if (class == PCI_CLASS_DISPLAY_VGA ||
@@ -1152,7 +1145,7 @@ check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga)
 static void __init
 do_fixup_p2p_level(struct pci_bus *bus)
 {
-       struct list_head *ln;
+       struct pci_bus *b;
        int i, parent_io;
        int has_vga = 0;
 
@@ -1163,8 +1156,7 @@ do_fixup_p2p_level(struct pci_bus *bus)
        if (parent_io >= 4)
                return;
 
-       for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
-               struct pci_bus *b = pci_bus_b(ln);
+       list_for_each_entry(b, &bus->children, node) {
                struct pci_dev *d = b->self;
                struct pci_controller* hose = (struct pci_controller *)d->sysdata;
                struct resource *res = b->resource[0];
@@ -1237,12 +1229,10 @@ do_fixup_p2p_level(struct pci_bus *bus)
 static void
 pcibios_fixup_p2p_bridges(void)
 {
-       struct list_head *ln;
+       struct pci_bus *b;
 
-       for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) {
-               struct pci_bus *b = pci_bus_b(ln);
+       list_for_each_entry(b, &pci_root_buses, node)
                do_fixup_p2p_level(b);
-       }
 }
 
 #endif /* CONFIG_PPC_PMAC */
@@ -1601,7 +1591,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        __pci_mmap_set_flags(dev, vma, mmap_state);
        __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
 
-       ret = remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+       ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                               vma->vm_end - vma->vm_start, vma->vm_page_prot);
 
        return ret;
index d8e027f..b5cd7e4 100644 (file)
@@ -21,9 +21,9 @@
 #include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 #include <asm/mmu.h>
 #include <asm/residual.h>
 #include <asm/io.h>
index e44d9a0..9bbb6bf 100644 (file)
@@ -133,7 +133,7 @@ Soft_emulate_8xx(struct pt_regs *regs)
                        print_8xx_pte(current->mm,regs->nip);
                        pa = get_8xx_pte(current->mm,regs->nip) & PAGE_MASK;
                        pa |= (regs->nip & ~PAGE_MASK);
-                       pa = __va(pa);
+                       pa = (unsigned long)__va(pa);
                        printk("Kernel VA for NIP %x ", pa);
                        print_8xx_pte(current->mm,pa);
                }
index 252beec..4ee8880 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #ifndef ATOMIC_DEC_AND_LOCK
-int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
        int counter;
        int newcount;
@@ -42,5 +42,5 @@ int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
        return 0;
 }
 
-EXPORT_SYMBOL(atomic_dec_and_lock);
+EXPORT_SYMBOL(_atomic_dec_and_lock);
 #endif /* ATOMIC_DEC_AND_LOCK */
index 9991c48..42c5de2 100644 (file)
@@ -645,6 +645,7 @@ int rh_set_owner(rh_info_t * info, void *start, const char *owner)
                return -EINVAL;
 
        blk->owner = owner;
+       size = blk->size;
 
        return size;
 }
index a2ab8b0..72f7c0d 100644 (file)
 #include <asm/setup.h>
 
 #include "mmu_decl.h"
-#include "mem_pieces.h"
 
 extern char etext[], _stext[];
-extern struct mem_pieces phys_avail;
 
 /* Used by the 44x TLB replacement exception handler.
  * Just needed it declared someplace.
@@ -105,16 +103,6 @@ unsigned long __init mmu_mapin_ram(void)
        unsigned int pinned_tlbs = 1;
        int i;
 
-       /*
-        * If lowmem is not on a pin tlb entry size boundary,
-        * then reserve the last page of system memory. This
-        * eliminates the possibility of a speculative dcache
-        * fetch past the end of system memory that would
-        * result in a machine check exception.
-        */
-       if (total_lowmem | (PPC44x_PIN_SIZE - 1))
-               mem_pieces_remove(&phys_avail, total_lowmem - PAGE_SIZE, PAGE_SIZE, 1);
-
        /* Determine number of entries necessary to cover lowmem */
        pinned_tlbs = (unsigned int)
                (_ALIGN(total_lowmem, PPC44x_PIN_SIZE) >> PPC44x_PIN_SHIFT);
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
+
+/******************************************************************/
index 9427584..b411c18 100644 (file)
@@ -77,6 +77,13 @@ struct ocp_def core_ocp[] = {
           .pm           = OCP_CPM_NA,
         },
         { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_SEC2,
+          .index        = 0,
+          .paddr        = MPC85xx_SEC2_OFFSET,
+          .irq          = MPC85xx_IRQ_SEC2,
+          .pm           = OCP_CPM_NA,
+       },
+       { .vendor       = OCP_VENDOR_FREESCALE,
           .function     = OCP_FUNC_PERFMON,
           .index        = 0,
           .paddr        = MPC85xx_PERFMON_OFFSET,
index 0cb2c34..64c9ce7 100644 (file)
@@ -145,12 +145,18 @@ mpc8560ads_setup_arch(void)
 
 static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
 {
-       while ((irq = cpm2_get_irq(regs)) >= 0) {
-               ppc_irq_dispatch_handler(regs, irq);
-       }
+       while ((irq = cpm2_get_irq(regs)) >= 0)
+               __do_IRQ(irq, regs);
        return IRQ_HANDLED;
 }
 
+static struct irqaction cpm2_irqaction = {
+       .handler = cpm2_cascade,
+       .flags = SA_INTERRUPT,
+       .mask = CPU_MASK_NONE,
+       .name = "cpm2_cascade",
+};
+
 static void __init
 mpc8560_ads_init_IRQ(void)
 {
@@ -174,7 +180,7 @@ mpc8560_ads_init_IRQ(void)
        immap->im_intctl.ic_scprrh = 0x05309770;
        immap->im_intctl.ic_scprrl = 0x05309770;
 
-       request_irq(MPC85xx_IRQ_CPM, cpm2_cascade, SA_INTERRUPT, "cpm2_cascade", NULL);
+       setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
 
        return;
 }
index 7f0fabc..45c8671 100644 (file)
@@ -142,8 +142,7 @@ mpc85xx_ads_show_cpuinfo(struct seq_file *m)
                seq_printf(m, "Machine\t\t: unknown\n");
                break;
        }
-       seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000,
-                  freq % 1000000);
+       seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
        seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
index 5eb6e42..1837da9 100644 (file)
@@ -172,8 +172,7 @@ mpc85xx_cds_show_cpuinfo(struct seq_file *m)
 
         seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
        seq_printf(m, "Machine\t\t: CDS (%x)\n", cadmus[CM_VER]);
-        seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000,
-                   freq % 1000000);
+       seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
         seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
         seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
@@ -191,10 +190,15 @@ mpc85xx_cds_show_cpuinfo(struct seq_file *m)
 static void cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
 {
        while((irq = cpm2_get_irq(regs)) >= 0)
-       {
-               ppc_irq_dispatch_handler(regs,irq);
-       }
+               __do_IRQ(irq, regs);
 }
+
+static struct irqaction cpm2_irqaction = {
+       .handler = cpm2_cascade,
+       .flags = SA_INTERRUPT,
+       .mask = CPU_MASK_NONE,
+       .name = "cpm2_cascade",
+};
 #endif /* CONFIG_CPM2 */
 
 void __init
@@ -237,7 +241,7 @@ mpc85xx_cds_init_IRQ(void)
        immap->im_intctl.ic_scprrh = 0x05309770;
        immap->im_intctl.ic_scprrl = 0x05309770;
 
-       request_irq(MPC85xx_IRQ_CPM, cpm2_cascade, SA_INTERRUPT, "cpm2_cascade", NULL);
+       setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
 #endif
 
         return;
index 8cc3323..110ae68 100644 (file)
@@ -142,8 +142,7 @@ sbc8560_show_cpuinfo(struct seq_file *m)
                seq_printf(m, "Machine\t\t: unknown\n");
                break;
        }
-       seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000,
-                  freq % 1000000);
+       seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
        seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
index ecdf123..9947cba 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/pci.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include <asm/io.h>
 #include <asm/i8259.h>
 static void adir_onboard_pic_enable(unsigned int irq);
 static void adir_onboard_pic_disable(unsigned int irq);
 
-static void
-no_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-}
-
 __init static void
 adir_onboard_pic_init(void)
 {
@@ -88,6 +83,13 @@ static struct hw_interrupt_type adir_onboard_pic = {
        NULL
 };
 
+static struct irqaction noop_action = {
+       .handler        = no_action,
+       .flags          = SA_INTERRUPT,
+       .mask           = CPU_MASK_NONE,
+       .name           = "82c59 primary cascade",
+};
+
 /*
  * Linux interrupt values are assigned as follows:
  *
@@ -110,11 +112,7 @@ adir_init_IRQ(void)
        adir_onboard_pic_init();
 
        /* Enable 8259 interrupt cascade */
-       request_irq(ADIR_IRQ_VT82C686_INTR,
-                       no_action,
-                       SA_INTERRUPT,
-                       "82c59 primary cascade",
-                       NULL);
+       setup_irq(ADIR_IRQ_VT82C686_INTR, &noop_action);
 }
 
 int
index e4ace97..9575938 100644 (file)
@@ -158,7 +158,7 @@ chrp_pcibios_fixup(void)
        struct device_node *np;
 
        /* PCI interrupts are controlled by the OpenPIC */
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                np = pci_device_to_OF_node(dev);
                if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0))
                        dev->irq = np->intrs[0].line;
index 3514bb9..03b3b3b 100644 (file)
@@ -371,6 +371,14 @@ static void __init chrp_find_openpic(void)
        }
 }
 
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+static struct irqaction xmon_irqaction = {
+       .handler = xmon_irq,
+       .mask = CPU_MASK_NONE,
+       .name = "XMON break",
+};
+#endif
+
 void __init chrp_init_IRQ(void)
 {
        struct device_node *np;
@@ -416,7 +424,7 @@ void __init chrp_init_IRQ(void)
                    && strcmp(kbd->parent->type, "adb") == 0)
                        break;
        if (kbd)
-               request_irq(HYDRA_INT_ADB_NMI, xmon_irq, 0, "XMON break", 0);
+               setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction);
 #endif
 }
 
index 17b251c..9565609 100644 (file)
@@ -15,7 +15,7 @@ void __init gemini_pcibios_fixup(void)
        int i;
        struct pci_dev *dev = NULL;
        
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                for(i = 0; i < 6; i++) {
                        if (dev->resource[i].flags & IORESOURCE_IO) {
                                dev->resource[i].start |= (0xfe << 24);
index 8a60203..be5c051 100644 (file)
@@ -116,7 +116,7 @@ void k2_pcibios_fixup(void)
        /*
         * Enable DMA support on hdc
         */
-       ide_dev = pci_find_device(PCI_VENDOR_ID_AL,
+       ide_dev = pci_get_device(PCI_VENDOR_ID_AL,
                                  PCI_DEVICE_ID_AL_M5229, NULL);
 
        if (ide_dev) {
@@ -126,6 +126,7 @@ void k2_pcibios_fixup(void)
                ide_dma_base = pci_resource_start(ide_dev, 4);
                outb(0x00, ide_dma_base + 0x2);
                outb(0x20, ide_dma_base + 0xa);
+               pci_dev_put(ide_dev);
        }
 #endif
 }
index 0037f5c..f0c2030 100644 (file)
@@ -189,7 +189,7 @@ static unsigned long lopec_idedma_regbase;
 static void
 lopec_ide_probe(void)
 {
-       struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+       struct pci_dev *dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
                                              PCI_DEVICE_ID_WINBOND_82C105,
                                              NULL);
        lopec_ide_ports_known = 1;
@@ -200,6 +200,7 @@ lopec_ide_probe(void)
                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;
+               pci_dev_put(dev);
        }
 }
 
index 348118b..83dcc8f 100644 (file)
@@ -185,7 +185,7 @@ mcpn765_setup_via_82c586b(void)
        struct pci_dev  *dev;
        u_char          c;
 
-       if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+       if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
                                   PCI_DEVICE_ID_VIA_82C586_0,
                                   NULL)) == NULL) {
                printk("No VIA ISA bridge found\n");
@@ -209,8 +209,8 @@ mcpn765_setup_via_82c586b(void)
        pci_write_config_dword(dev, 0x54, 0);
        pci_write_config_byte(dev, 0x58, 0);
 
-
-       if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+       pci_dev_put(dev);
+       if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
                                   PCI_DEVICE_ID_VIA_82C586_1,
                                   NULL)) == NULL) {
                printk("No VIA ISA bridge found\n");
@@ -225,6 +225,7 @@ mcpn765_setup_via_82c586b(void)
        pci_read_config_byte(dev, 0x40, &c);
        c |= 0x03;
        pci_write_config_byte(dev, 0x40, c);
+       pci_dev_put(dev);
 
        return;
 }
index b08be24..0ecea91 100644 (file)
@@ -228,7 +228,7 @@ mvme5100_init_IRQ(void)
        for (i = 0; i < NUM_8259_INTERRUPTS; i++)
                irq_desc[i].handler = &i8259_pic;
 
-       i8259_init(NULL);
+       i8259_init(0);
 #else
        openpic_init(0);
 #endif
index da022ec..af8b51d 100644 (file)
@@ -89,7 +89,7 @@ pcore_pcibios_fixup(void)
 {
        struct pci_dev *dev;
 
-       if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+       if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
                                PCI_DEVICE_ID_WINBOND_83C553,
                                0)))
        {
@@ -108,6 +108,7 @@ pcore_pcibios_fixup(void)
                 */
                outb(0x00, PCORE_WINBOND_PRI_EDG_LVL);
                outb(0x1e, PCORE_WINBOND_SEC_EDG_LVL);
+               pci_dev_put(dev);
        }
 }
 
index 4e53bea..0b67361 100644 (file)
@@ -889,7 +889,7 @@ pcibios_fixup_OF_interrupts(void)
         * should find the device node and apply the interrupt
         * obtained from the OF device-tree
         */
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                struct device_node *node;
                node = pci_device_to_OF_node(dev);
                /* this is the node, see if it has interrupts */
@@ -989,7 +989,7 @@ pmac_pcibios_after_init(void)
         *
         * -- BenH
         */
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE)
                        pci_enable_device(dev);
        }
index 1a300ff..d6624b0 100644 (file)
@@ -405,6 +405,13 @@ static void __init psurge_dual_sync_tb(int cpu_nr)
        smp_tb_synchronized = 1;
 }
 
+static struct irqaction psurge_irqaction = {
+       .handler = psurge_primary_intr,
+       .flags = SA_INTERRUPT,
+       .mask = CPU_MASK_NONE,
+       .name = "primary IPI",
+};
+
 static void __init smp_psurge_setup_cpu(int cpu_nr)
 {
 
@@ -421,7 +428,7 @@ static void __init smp_psurge_setup_cpu(int cpu_nr)
                /* reset the entry point so if we get another intr we won't
                 * try to startup again */
                out_be32(psurge_start, 0x100);
-               if (request_irq(30, psurge_primary_intr, SA_INTERRUPT, "primary IPI", NULL))
+               if (setup_irq(30, &psurge_irqaction))
                        printk(KERN_ERR "Couldn't get primary IPI interrupt");
        }
 
index a528562..5dce242 100644 (file)
@@ -49,10 +49,10 @@ static char Utah_pci_IRQ_map[23] __prepdata =
         0,   /* Slot 1  - unused */
         5,   /* Slot 2  - SCSI - NCR825A  */
         0,   /* Slot 3  - unused */
-        1,   /* Slot 4  - Ethernet - DEC2114x */
+        3,   /* Slot 4  - Ethernet - DEC2114x */
         0,   /* Slot 5  - unused */
-        3,   /* Slot 6  - PCI Card slot #1 */
-        4,   /* Slot 7  - PCI Card slot #2 */
+        2,   /* Slot 6  - PCI Card slot #1 */
+        3,   /* Slot 7  - PCI Card slot #2 */
         5,   /* Slot 8  - PCI Card slot #3 */
         5,   /* Slot 9  - PCI Bridge */
              /* added here in case we ever support PCI bridges */
@@ -1069,7 +1069,7 @@ prep_pib_init(void)
                 * Perform specific configuration for the Via Tech or
                 * or Winbond PCI-ISA-Bridge part.
                 */
-               if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+               if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
                                        PCI_DEVICE_ID_VIA_82C586_1, dev))) {
                        /*
                         * PPCBUG does not set the enable bits
@@ -1080,7 +1080,7 @@ prep_pib_init(void)
                        reg |= 0x03; /* IDE: Chip Enable Bits */
                        pci_write_config_byte(dev, 0x40, reg);
                }
-               if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+               if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
                                                PCI_DEVICE_ID_VIA_82C586_2,
                                                dev)) && (dev->devfn = 0x5a)) {
                        /* Force correct USB interrupt */
@@ -1089,7 +1089,7 @@ prep_pib_init(void)
                                        PCI_INTERRUPT_LINE,
                                        dev->irq);
                }
-               if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+               if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
                                        PCI_DEVICE_ID_WINBOND_83C553, dev))) {
                         /* Clear PCI Interrupt Routing Control Register. */
                        short_reg = 0x0000;
@@ -1100,9 +1100,10 @@ prep_pib_init(void)
                                pci_write_config_byte(dev, 0x43, reg);
                        }
                }
+               pci_dev_put(dev);
        }
 
-       if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+       if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
                                   PCI_DEVICE_ID_WINBOND_82C105, dev))){
                if (OpenPIC_Addr){
                        /*
@@ -1121,6 +1122,7 @@ prep_pib_init(void)
                        pci_write_config_dword(dev, 0x40, 0x10ff08a1);
                }
        }
+       pci_dev_put(dev);
 }
 
 static void __init
@@ -1207,7 +1209,7 @@ prep_pcibios_fixup(void)
        printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
 
        /* Iterate through all the PCI devices, setting the IRQ */
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                /*
                 * If we have residual data, then this is easy: query the
                 * residual data for the IRQ line allocated to the device.
@@ -1260,12 +1262,13 @@ prep_pcibios_after_init(void)
         * instead of 0xc0000. vgacon.c (for example) is completely unaware of
         * this little quirk.
         */
-       dev = pci_find_device(PCI_VENDOR_ID_WD, PCI_DEVICE_ID_WD_90C, NULL);
+       dev = pci_get_device(PCI_VENDOR_ID_WD, PCI_DEVICE_ID_WD_90C, NULL);
        if (dev) {
                dev->resource[1].end -= dev->resource[1].start;
                dev->resource[1].start = 0;
                /* tell the hardware */
                pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0x0);
+               pci_dev_put(dev);
        }
 #endif
 }
index a75553c..b89d144 100644 (file)
@@ -109,7 +109,7 @@ static void __init prpmc750_pcibios_fixup(void)
         * resource subsystem doesn't fixup the
         * PCI mem resources on the CL5446.
         */
-       if ((dev = pci_find_device(PCI_VENDOR_ID_CIRRUS,
+       if ((dev = pci_get_device(PCI_VENDOR_ID_CIRRUS,
                                   PCI_DEVICE_ID_CIRRUS_5446, 0))) {
                dev->resource[0].start += PRPMC750_PCI_PHY_MEM_OFFSET;
                dev->resource[0].end += PRPMC750_PCI_PHY_MEM_OFFSET;
@@ -121,6 +121,7 @@ static void __init prpmc750_pcibios_fixup(void)
                outb(0x0f, 0x3c4);
                /* Set proper DRAM config */
                outb(0xdf, 0x3c5);
+               pci_dev_put(dev);
        }
 }
 
index d1d81b8..6daa109 100644 (file)
@@ -82,7 +82,6 @@ extern bd_t m8xx_board_info;
 /* for pcmcia sandisk */
 #ifdef CONFIG_IDE
 # define MAX_HWIFS 1
-# define request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
 #endif
 #endif
 
index 69646bf..deee5bd 100644 (file)
@@ -68,7 +68,6 @@ extern bd_t m8xx_board_info;
 
 #ifdef CONFIG_IDE
 # define MAX_HWIFS 1
-# define request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
 #endif
 
 /* CPM Ethernet through SCCx.
index f69b306..2150dc8 100644 (file)
@@ -72,8 +72,6 @@ static __inline__ void ide_led(int on)
 #define        IDE0_INTERRUPT          13
 
 #ifdef CONFIG_IDE
-#define ide_request_irq(irq,hand,flg,dev,id)    \
-        request_8xxirq((irq),(hand),(flg),(dev),(id))
 #endif
 
 /*-----------------------------------------------------------------------
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);
index 4692ba7..dc2365c 100644 (file)
@@ -40,12 +40,12 @@ static int shift;
 
 unsigned long direct_inb(unsigned long addr)
 {
-       return readb(addr);
+       return readb((void __iomem *)addr);
 }
 
 void direct_outb(unsigned long addr, unsigned char val)
 {
-       writeb(val, addr);
+       writeb(val, (void __iomem *)addr);
 }
 
 unsigned long io_inb(unsigned long port)
index 232044c..7239d5d 100644 (file)
@@ -9,9 +9,9 @@
  *
  * Adapted from ppc4xx_kgdb.c.
  *
- * Author: Matt Porter <mporter@mvista.com>
+ * Author: Matt Porter <mporter@kernel.crashing.org>
  *
- * 2002-2003 (c) MontaVista Software, Inc.  This file is licensed under
+ * 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.
@@ -80,5 +80,7 @@ void
 gen550_kgdb_map_scc(void)
 {
        printk(KERN_DEBUG "kgdb init\n");
+       if (ppc_md.early_serial_map)
+               ppc_md.early_serial_map();
        kgdb_debugport = serial_init(KGDB_PORT, NULL);
 }
index c6c361b..c660f40 100644 (file)
@@ -151,6 +151,13 @@ static struct resource pic_edgectrl_iores = {
        "8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY
 };
 
+static struct irqaction i8259_irqaction = {
+       .handler = no_action,
+       .flags = SA_INTERRUPT,
+       .mask = CPU_MASK_NONE,
+       .name = "82c59 secondary cascade",
+};
+
 /*
  * i8259_init()
  * intack_addr - PCI interrupt acknowledge (real) address which will return
@@ -185,8 +192,7 @@ i8259_init(long intack_addr)
        spin_unlock_irqrestore(&i8259_lock, flags);
 
        /* reserve our resources */
-       request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT,
-                               "82c59 secondary cascade", NULL );
+       setup_irq( i8259_pic_irq_offset + 2, &i8259_irqaction);
        request_resource(&ioport_resource, &pic1_iores);
        request_resource(&ioport_resource, &pic2_iores);
        request_resource(&ioport_resource, &pic_edgectrl_iores);
index 5da7bca..5e2ce6b 100644 (file)
@@ -4,7 +4,7 @@
  * PPC440GX system library
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
- * Copyright (c) 2003 Zultys Technologies
+ * Copyright (c) 2003, 2004 Zultys Technologies
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -14,6 +14,7 @@
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/interrupt.h>
 #include <asm/ibm44x.h>
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -97,10 +98,51 @@ bypass:
                p->uart1 = p->plb / __fix_zero(uart1 & 0xff, 256);
 }
 
-/* Enable L2 cache (call with IRQs disabled) */
+/* Issue L2C diagnostic command */
+static inline u32 l2c_diag(u32 addr)
+{
+       mtdcr(DCRN_L2C0_ADDR, addr);
+       mtdcr(DCRN_L2C0_CMD, L2C_CMD_DIAG);
+       while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ;
+       return mfdcr(DCRN_L2C0_DATA);
+}
+
+static irqreturn_t l2c_error_handler(int irq, void* dev, struct pt_regs* regs)
+{
+       u32 sr = mfdcr(DCRN_L2C0_SR);
+       if (sr & L2C_SR_CPE){
+               /* Read cache trapped address */
+               u32 addr = l2c_diag(0x42000000);
+               printk(KERN_EMERG "L2C: Cache Parity Error, addr[16:26] = 0x%08x\n", addr);
+       }
+       if (sr & L2C_SR_TPE){
+               /* Read tag trapped address */
+               u32 addr = l2c_diag(0x82000000) >> 16;
+               printk(KERN_EMERG "L2C: Tag Parity Error, addr[16:26] = 0x%08x\n", addr);
+       }
+
+       /* Clear parity errors */
+       if (sr & (L2C_SR_CPE | L2C_SR_TPE)){
+               mtdcr(DCRN_L2C0_ADDR, 0);
+               mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
+       } else
+               printk(KERN_EMERG "L2C: LRU error\n");
+
+       return IRQ_HANDLED;
+}
+
+/* Enable L2 cache */
 void __init ibm440gx_l2c_enable(void){
        u32 r;
+       unsigned long flags;
+
+       /* Install error handler */
+       if (request_irq(87, l2c_error_handler, SA_INTERRUPT, "L2C", 0) < 0){
+               printk(KERN_ERR "Cannot install L2C error handler, cache is not enabled\n");
+               return;
+       }
 
+       local_irq_save(flags);
        asm volatile ("sync" ::: "memory");
 
        /* Disable SRAM */
@@ -137,20 +179,22 @@ void __init ibm440gx_l2c_enable(void){
 
        /* Enable ICU/DCU ports */
        r = mfdcr(DCRN_L2C0_CFG);
-       r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM
-               | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM | L2C_CFG_TPEI | L2C_CFG_CPEI
-               | L2C_CFG_NAM | L2C_CFG_NBRM);
+       r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM | L2C_CFG_TPEI
+               | L2C_CFG_CPEI | L2C_CFG_NAM | L2C_CFG_NBRM);
        r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN
-               | L2C_CFG_SMCM;
+               | L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM | L2C_CFG_SMCM;
        mtdcr(DCRN_L2C0_CFG, r);
 
        asm volatile ("sync; isync" ::: "memory");
+       local_irq_restore(flags);
 }
 
-/* Disable L2 cache (call with IRQs disabled) */
+/* Disable L2 cache */
 void __init ibm440gx_l2c_disable(void){
        u32 r;
+       unsigned long flags;
 
+       local_irq_save(flags);
        asm volatile ("sync" ::: "memory");
 
        /* Disable L2C mode */
@@ -169,6 +213,20 @@ void __init ibm440gx_l2c_disable(void){
              SRAM_SBCR_BAS3 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
 
        asm volatile ("sync; isync" ::: "memory");
+       local_irq_restore(flags);
+}
+
+void __init ibm440gx_l2c_setup(struct ibm44x_clocks* p)
+{
+       /* Disable L2C on rev.A, rev.B and 800MHz version of rev.C,
+          enable it on all other revisions
+        */
+       u32 pvr = mfspr(PVR);
+       if (pvr == PVR_440GX_RA || pvr == PVR_440GX_RB ||
+           (pvr == PVR_440GX_RC && p->cpu > 667000000))
+               ibm440gx_l2c_disable();
+       else
+               ibm440gx_l2c_enable();
 }
 
 int __init ibm440gx_get_eth_grp(void)
index 5dbca98..e73aa04 100644 (file)
@@ -4,7 +4,7 @@
  * PPC440GX system library
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
- * Copyright (c) 2003 Zultys Technologies
+ * Copyright (c) 2003, 2004 Zultys Technologies
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -37,6 +37,9 @@ void ibm440gx_l2c_enable(void) __init;
 /* Disable L2 cache */
 void ibm440gx_l2c_disable(void) __init;
 
+/* Enable/disable L2 cache for a particular chip revision */
+void ibm440gx_l2c_setup(struct ibm44x_clocks*) __init;
+
 /* Get Ethernet Group */
 int ibm440gx_get_eth_grp(void) __init;
 
index 76d18d3..4029c43 100644 (file)
@@ -3,8 +3,8 @@
  *
  * PPC44x system library
  *
- * Matt Porter <mporter@mvista.com>
- * Copyright 2002-2003 MontaVista Software Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2002-2004 MontaVista Software Inc.
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  * Copyright (c) 2003, 2004 Zultys Technologies
  *
  */
 #include <linux/config.h>
+#include <linux/time.h>
 #include <linux/types.h>
 #include <linux/serial.h>
 
-#include <asm/param.h>
 #include <asm/ibm44x.h>
 #include <asm/mmu.h>
 #include <asm/machdep.h>
 #include <asm/time.h>
 #include <asm/ppc4xx_pic.h>
+#include <asm/param.h>
+
+#include <syslib/gen550.h>
 
 phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size)
 {
@@ -149,44 +152,6 @@ static void __init ibm44x_init_irq(void)
                irq_desc[i].handler = ppc4xx_pic;
 }
 
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-#include <asm/serial.h>
-
-static struct serial_state rs_table[RS_TABLE_SIZE] = {
-       SERIAL_PORT_DFNS        /* Defined in <asm/serial.h> */
-};
-
-static void ibm44x_progress(char *s, unsigned short hex)
-{
-       volatile char c;
-       volatile unsigned long com_port;
-       u16 shift;
-
-       com_port = (unsigned long)rs_table[0].iomem_base;
-       shift = rs_table[0].iomem_reg_shift;
-
-       while ((c = *s++) != 0) {
-               while ((*((volatile unsigned char *)com_port +
-                               (UART_LSR << shift)) & UART_LSR_THRE) == 0)
-                       ;
-               *(volatile unsigned char *)com_port = c;
-
-       }
-
-       /* Send LF/CR to pretty up output */
-       while ((*((volatile unsigned char *)com_port +
-               (UART_LSR << shift)) & UART_LSR_THRE) == 0)
-               ;
-       *(volatile unsigned char *)com_port = '\r';
-       while ((*((volatile unsigned char *)com_port +
-               (UART_LSR << shift)) & UART_LSR_THRE) == 0)
-               ;
-       *(volatile unsigned char *)com_port = '\n';
-}
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
-
 void __init ibm44x_platform_init(void)
 {
        ppc_md.init_IRQ = ibm44x_init_irq;
@@ -196,7 +161,22 @@ void __init ibm44x_platform_init(void)
        ppc_md.halt = ibm44x_halt;
 
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
-       ppc_md.progress = ibm44x_progress;
+       ppc_md.progress = gen550_progress;
 #endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#ifdef CONFIG_KGDB
+       ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
+#endif
+
+       /*
+        * The Abatron BDI JTAG debugger does not tolerate others
+        * mucking with the debug registers.
+        */
+#if !defined(CONFIG_BDI_SWITCH)
+       /* Enable internal debug mode */
+        mtspr(SPRN_DBCR0, (DBCR0_IDM));
+
+       /* Clear any residual debug events */
+       mtspr(SPRN_DBSR, 0xffffffff);
+#endif
 }
 
index 4bc90eb..1cc4f96 100644 (file)
@@ -111,6 +111,15 @@ static struct pci_ops indirect_pci_ops =
        indirect_write_config
 };
 
+void __init
+setup_indirect_pci_nomap(struct pci_controller* hose, u32 cfg_addr,
+       u32 cfg_data)
+{
+       hose->cfg_addr = (unsigned int *)cfg_addr;
+       hose->cfg_data = (unsigned char *)cfg_data;
+       hose->ops = &indirect_pci_ops;
+}
+
 void __init
 setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
 {
@@ -118,9 +127,9 @@ setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
        char *mbase;
 
        mbase = ioremap(base, PAGE_SIZE);
-       hose->cfg_addr = (unsigned int *)(mbase + (cfg_addr & ~PAGE_MASK));
+       cfg_addr = (u32)(mbase + (cfg_addr & ~PAGE_MASK));
        if ((cfg_data & PAGE_MASK) != base)
                mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
-       hose->cfg_data = (unsigned char *)(mbase + (cfg_data & ~PAGE_MASK));
-       hose->ops = &indirect_pci_ops;
+       cfg_data = (u32)(mbase + (cfg_data & ~PAGE_MASK));
+       setup_indirect_pci_nomap(hose, cfg_addr, cfg_data);
 }
index d73e6fe..6bd014d 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/config.h>
 
+#include <asm/io.h>
 #include <asm/time.h>
 #include <asm/mpc52xx.h>
 #include <asm/mpc52xx_psc.h>
index b2f3d85..89f6825 100644 (file)
@@ -466,7 +466,7 @@ ppc4xx_init_dma_channel(unsigned int dmanr, ppc_dma_ch_t * p_init)
 
        /* clear all polarity signals and then "or" in new signal levels */
        polarity &= ~GET_DMA_POLARITY(dmanr);
-       polarity |= p_dma_ch->polarity;
+       polarity |= p_init->polarity;
 #if DCRN_POL > 0
        mtdcr(DCRN_POL, polarity);
 #endif
index 735f3ae..5385e76 100644 (file)
@@ -42,6 +42,8 @@
 #include <asm/pci-bridge.h>
 #include <asm/bootinfo.h>
 
+#include <syslib/gen550.h>
+
 /* Function Prototypes */
 extern void abort(void);
 extern void ppc4xx_find_bridges(void);
@@ -56,8 +58,16 @@ bd_t __res;
 void __init
 ppc4xx_setup_arch(void)
 {
-       /* Setup PCI host bridges */
+#if !defined(CONFIG_BDI_SWITCH)
+       /*
+        * The Abatron BDI JTAG debugger does not tolerate others
+        * mucking with the debug registers.
+        */
+        mtspr(SPRN_DBCR0, (DBCR0_IDM));
+       mtspr(SPRN_DBSR, 0xffffffff);
+#endif
 
+       /* Setup PCI host bridges */
 #ifdef CONFIG_PCI
        ppc4xx_find_bridges();
 #endif
@@ -189,34 +199,6 @@ ppc4xx_calibrate_decr(void)
        /* Set the PIT reload value and just let it run. */
        mtspr(SPRN_PIT, tb_ticks_per_jiffy);
 }
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-
-/* We assume that the UART has already been initialized by the
-   firmware or the boot loader */
-static void
-serial_putc(u8 * com_port, unsigned char c)
-{
-       while ((readb(com_port + (UART_LSR)) & UART_LSR_THRE) == 0) ;
-       writeb(c, com_port);
-}
-
-static void
-ppc4xx_progress(char *s, unsigned short hex)
-{
-       char c;
-#ifdef SERIAL_DEBUG_IO_BASE
-       u8 *com_port = (u8 *) SERIAL_DEBUG_IO_BASE;
-
-       while ((c = *s++) != '\0') {
-               serial_putc(com_port, c);
-       }
-       serial_putc(com_port, '\r');
-       serial_putc(com_port, '\n');
-#else
-       printk("%s\r\n");
-#endif
-}
-#endif                         /* CONFIG_SERIAL_TEXT_DEBUG */
 
 /*
  * IDE stuff.
@@ -319,13 +301,9 @@ ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.setup_io_mappings = ppc4xx_map_io;
 
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
-       ppc_md.progress = ppc4xx_progress;
+       ppc_md.progress = gen550_progress;
 #endif
 
-/*
-**   m8xx_setup.c, prep_setup.c use
-**     defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-*/
 #if defined(CONFIG_PCI) && defined(CONFIG_IDE)
        ppc_ide_md.ide_init_hwif = ppc4xx_ide_init_hwif_ports;
 #endif /* defined(CONFIG_PCI) && defined(CONFIG_IDE) */
index 8481a41..d3b01c6 100644 (file)
@@ -4,11 +4,14 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
+#include <linux/interrupt.h>
 #include <asm/irq.h>
 #include <asm/8xx_immap.h>
 #include <asm/mpc8xx.h>
 #include "ppc8xx_pic.h"
 
+extern int cpm_get_irq(struct pt_regs *regs);
+
 /* The 8xx internal interrupt controller.  It is usually
  * the only interrupt controller.  Some boards, like the MBX and
  * Sandpoint have the 8259 as a secondary controller.  Depending
@@ -72,46 +75,13 @@ static void m8xx_mask_and_ack(unsigned int irq_nr)
 }
 
 struct hw_interrupt_type ppc8xx_pic = {
-       " 8xx SIU  ",
-       NULL,
-       NULL,
-       m8xx_unmask_irq,
-       m8xx_mask_irq,
-       m8xx_mask_and_ack,
-       m8xx_end_irq,
-       0
+       .typename = " 8xx SIU  ",
+       .enable = m8xx_unmask_irq,
+       .disable = m8xx_mask_irq,
+       .ack = m8xx_mask_and_ack,
+       .end = m8xx_end_irq,
 };
 
-#if 0
-void
-m8xx_do_IRQ(struct pt_regs *regs,
-          int            cpu)
-{
-       int irq;
-        unsigned long bits = 0;
-
-        /* For MPC8xx, read the SIVEC register and shift the bits down
-         * to get the irq number.         */
-        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
-        irq = bits >> 26;
-#if 0
-        irq += ppc8xx_pic.irq_offset;
-#endif
-        bits = 1UL << irq;
-
-       if (irq < 0) {
-               printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-                      irq, regs->nip);
-               ppc_spurious_interrupts++;
-       }
-       else {
-                ppc_irq_dispatch_handler( regs, irq );
-       }
-
-}
-#endif
-
-
 /*
  * We either return a valid interrupt or -1 if there is nothing pending
  */
@@ -129,73 +99,32 @@ m8xx_get_irq(struct pt_regs *regs)
         * When we read the sivec without an interrupt to process, we will
         * get back SIU_LEVEL7.  In this case, return -1
         */
-       if (irq == SIU_LEVEL7)
-               return -1;
+        if (irq == CPM_INTERRUPT)
+               irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
+#if defined(CONFIG_PCI)
+       else if (irq == ISA_BRIDGE_INT) {
+               int isa_irq;
+
+               if ((isa_irq = i8259_poll(regs)) >= 0)
+                       irq = I8259_IRQ_OFFSET + isa_irq;
+       }
+#endif /* CONFIG_PCI */
+       else if (irq == SIU_LEVEL7)
+               irq = -1;
 
        return irq;
 }
 
-/* The MBX is the only 8xx board that uses the 8259.
-*/
 #if defined(CONFIG_MBX) && defined(CONFIG_PCI)
-void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-       int bits, irq;
-
-       /* A bug in the QSpan chip causes it to give us 0xff always
-        * when doing a character read.  So read 32 bits and shift.
-        * This doesn't seem to return useful values anyway, but
-        * read it to make sure things are acked.
-        * -- Cort
-        */
-       irq = (inl(0x508) >> 24)&0xff;
-       if ( irq != 0xff ) printk("iack %d\n", irq);
-
-       outb(0x0C, 0x20);
-       irq = inb(0x20) & 7;
-       if (irq == 2)
-       {
-               outb(0x0C, 0xA0);
-               irq = inb(0xA0);
-               irq = (irq&7) + 8;
-       }
-       bits = 1UL << irq;
-       irq += i8259_pic.irq_offset;
-       ppc_irq_dispatch_handler( regs, irq );
-}
-#endif
-
 /* Only the MBX uses the external 8259.  This allows us to catch standard
  * drivers that may mess up the internal interrupt controllers, and also
  * allow them to run without modification on the MBX.
  */
-int request_irq(unsigned int irq,
-       irqreturn_t (*handler)(int, void *, struct pt_regs *),
-       unsigned long irqflags, const char * devname, void *dev_id)
+void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
 {
-
-#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
-       irq += i8259_pic.irq_offset;
-       return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
-#else
-       /*
-        * Handle other "well-known" interrupts, but panic on unknown ones.
+       /* This interrupt handler never actually gets called.  It is
+        * installed only to unmask the 8259 cascade interrupt in the SIU
+        * and to make the 8259 cascade interrupt visible in /proc/interrupts.
         */
-       switch (irq) {
-#ifdef IDE0_INTERRUPT
-               case IDE0_INTERRUPT:    /* IDE0 */
-                       return (request_8xxirq(irq, handler, irqflags, devname,
-                                               dev_id));
-#endif
-#ifdef IDE1_INTERRUPT
-               case IDE1_INTERRUPT:    /* IDE1 */
-                       return (request_8xxirq(irq, handler, irqflags, devname,
-                                               dev_id));
-#endif
-       default:                        /* unknown IRQ -> panic */
-               panic("request_irq");
-       }
-#endif
 }
-
-EXPORT_SYMBOL(request_irq);
+#endif /* CONFIG_PCI */
index 1ddb0c0..1b23f1e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/bitops.h>
 
 #include <asm/sections.h>
 #include <asm/prom.h>
@@ -31,7 +32,6 @@
 #include <asm/system.h>
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
-#include <asm/bitops.h>
 #include <asm/bootinfo.h>
 #include <asm/btext.h>
 #include <asm/pci-bridge.h>
index 1dc7e0b..0165e18 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/bcd.h>
+#include <linux/mc146818rtc.h>
 
 #include <asm/machdep.h>
 #include <asm/io.h>
@@ -48,8 +49,6 @@
  *                                             --MAG
  */
 
-extern spinlock_t      rtc_lock;
-
 /*
  * 'todc_info' should be initialized in your *_setup.c file to
  * point to a fully initialized 'todc_info_t' structure.
@@ -82,13 +81,13 @@ extern spinlock_t   rtc_lock;
 u_char
 todc_direct_read_val(int addr)
 {
-       return readb(todc_info->nvram_data + addr);
+       return readb((void __iomem *)(todc_info->nvram_data + addr));
 }
 
 void
 todc_direct_write_val(int addr, unsigned char val)
 {
-       writeb(val, todc_info->nvram_data + addr);
+       writeb(val, (void __iomem *)(todc_info->nvram_data + addr));
        return;
 }
 
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;
+}
index d880967..8d3fde1 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/sysrq.h>
+#include <linux/bitops.h>
 #include <asm/xmon.h>
 #include <asm/prom.h>
 #include <asm/bootx.h>
@@ -21,9 +22,6 @@
 #include <asm/processor.h>
 #include <asm/delay.h>
 #include <asm/btext.h>
-#ifdef CONFIG_SMP
-#include <asm/bitops.h>
-#endif
 
 static volatile unsigned char *sccc, *sccd;
 unsigned int TXRDY, RXRDY, DLAB;
@@ -104,7 +102,7 @@ static struct sysrq_key_op sysrq_xmon_op =
 {
        .handler =      sysrq_handle_xmon,
        .help_msg =     "Xmon",
-       .action_msg =   "Entering xmon\n",
+       .action_msg =   "Entering xmon",
 };
 #endif
 
index e7fe8d4..9976e7c 100644 (file)
@@ -8,10 +8,10 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
+#include <linux/bitops.h>
 #include <asm/ptrace.h>
 #include <asm/string.h>
 #include <asm/prom.h>
-#include <asm/bitops.h>
 #include <asm/bootx.h>
 #include <asm/machdep.h>
 #include <asm/xmon.h>
index c3cd4c7..be2d879 100644 (file)
@@ -44,16 +44,4 @@ config IRQSTACKS
          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
index 2f2b9bf..3458cf0 100644 (file)
@@ -23,7 +23,8 @@ unsigned char cached_8259[2] = { 0xff, 0xff };
 
 static spinlock_t i8259_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
-int i8259_pic_irq_offset;
+static int i8259_pic_irq_offset;
+static int i8259_present;
 
 int i8259_irq(int cpu)
 {
@@ -140,11 +141,13 @@ struct hw_interrupt_type i8259_pic = {
         NULL
 };
 
-void __init i8259_init(void)
+void __init i8259_init(int offset)
 {
        unsigned long flags;
        
        spin_lock_irqsave(&i8259_lock, flags);
+       i8259_pic_irq_offset = offset;
+       i8259_present = 1;
         /* init master interrupt controller */
         outb(0x11, 0x20); /* Start init sequence */
         outb(0x00, 0x21); /* Vector base */
@@ -160,7 +163,18 @@ void __init i8259_init(void)
         outb(cached_A1, 0xA1);
         outb(cached_21, 0x21);
        spin_unlock_irqrestore(&i8259_lock, flags);
+        
+}
+
+static int i8259_request_cascade(void)
+{
+       if (!i8259_present)
+               return -ENODEV;
+
         request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT,
                      "82c59 secondary cascade", NULL );
-        
+
+       return 0;
 }
+
+arch_initcall(i8259_request_cascade);
index 620a999..f74764b 100644 (file)
@@ -11,7 +11,7 @@
 
 extern struct hw_interrupt_type i8259_pic;
 
-void i8259_init(void);
-int i8259_irq(int);
+extern void i8259_init(int offset);
+extern int i8259_irq(int);
 
 #endif /* _PPC_KERNEL_i8259_H */
index c09ea2a..4f06318 100644 (file)
  * 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 <asm/io.h>
-#include <asm/prom.h>
-#include <asm/rtas.h>
-#include <asm/ppcdebug.h>
+#include <linux/list.h>
 
-#include <asm/iSeries/HvCallXm.h>
-#include <asm/iSeries/LparData.h>
 #include <asm/iommu.h>
-#include <asm/pci-bridge.h>
-#include <asm/iSeries/iSeries_pci.h>
-
 #include <asm/machdep.h>
-
-#include "pci.h"
-
+#include <asm/iSeries/HvCallXm.h>
+#include <asm/iSeries/iSeries_pci.h>
 
 extern struct list_head iSeries_Global_Device_List;
 
@@ -76,12 +60,11 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
                                tce.te_bits.tb_pciwr = 1;
                }
 
-               rc = HvCallXm_setTce((u64)tbl->it_index,
-                                    (u64)index,
-                                    tce.te_word);
+               rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index,
+                               tce.te_word);
                if (rc)
-                       panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", rc);
-
+                       panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n",
+                                       rc);
                index++;
                uaddr += PAGE_SIZE;
        }
@@ -90,20 +73,14 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
 static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
 {
        u64 rc;
-       union tce_entry tce;
 
        while (npages--) {
-               tce.te_word = 0;
-               rc = HvCallXm_setTce((u64)tbl->it_index,
-                                    (u64)index,
-                                    tce.te_word);
-
+               rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0);
                if (rc)
-                       panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", rc);
-
+                       panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n",
+                                       rc);
                index++;
        }
-
 }
 
 
@@ -115,17 +92,14 @@ static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
 {
        struct iSeries_Device_Node *dp;
 
-       for (dp =  (struct iSeries_Device_Node *)iSeries_Global_Device_List.next;
-            dp != (struct iSeries_Device_Node *)&iSeries_Global_Device_List;
-            dp =  (struct iSeries_Device_Node *)dp->Device_List.next)
-               if (dp->iommu_table                 != NULL &&
-                   dp->iommu_table->it_type        == TCE_PCI &&
-                   dp->iommu_table->it_offset      == tbl->it_offset &&
-                   dp->iommu_table->it_index       == tbl->it_index &&
-                   dp->iommu_table->it_size        == tbl->it_size)
+       list_for_each_entry(dp, &iSeries_Global_Device_List, Device_List) {
+               if ((dp->iommu_table != NULL) &&
+                   (dp->iommu_table->it_type == TCE_PCI) &&
+                   (dp->iommu_table->it_offset == tbl->it_offset) &&
+                   (dp->iommu_table->it_index == tbl->it_index) &&
+                   (dp->iommu_table->it_size == tbl->it_size))
                        return dp->iommu_table;
-
-
+       }
        return NULL;
 }
 
@@ -143,15 +117,14 @@ static void iommu_table_getparms(struct iSeries_Device_Node* dn,
 {
        struct iommu_table_cb *parms;
 
-       parms = (struct iommu_table_cb*)kmalloc(sizeof(*parms), GFP_KERNEL);
-
+       parms = kmalloc(sizeof(*parms), GFP_KERNEL);
        if (parms == NULL)
                panic("PCI_DMA: TCE Table Allocation failed.");
 
        memset(parms, 0, sizeof(*parms));
 
-       parms->itc_busno   = ISERIES_BUS(dn);
-       parms->itc_slotno  = dn->LogicalSlot;
+       parms->itc_busno = ISERIES_BUS(dn);
+       parms->itc_slotno = dn->LogicalSlot;
        parms->itc_virtbus = 0;
 
        HvCallXm_getTceTableParms(ISERIES_HV_ADDR(parms));
@@ -159,34 +132,32 @@ static void iommu_table_getparms(struct iSeries_Device_Node* dn,
        if (parms->itc_size == 0)
                panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
 
-       tbl->it_size        = parms->itc_size;
-       tbl->it_busno       = parms->itc_busno;
-       tbl->it_offset      = parms->itc_offset;
-       tbl->it_index       = parms->itc_index;
-       tbl->it_entrysize   = sizeof(union tce_entry);
-       tbl->it_blocksize   = 1;
-       tbl->it_type        = TCE_PCI;
+       tbl->it_size = parms->itc_size;
+       tbl->it_busno = parms->itc_busno;
+       tbl->it_offset = parms->itc_offset;
+       tbl->it_index = parms->itc_index;
+       tbl->it_entrysize = sizeof(union tce_entry);
+       tbl->it_blocksize = 1;
+       tbl->it_type = TCE_PCI;
 
        kfree(parms);
 }
 
 
-void iommu_devnode_init(struct iSeries_Device_Node *dn) {
+void iommu_devnode_init_iSeries(struct iSeries_Device_Node *dn)
+{
        struct iommu_table *tbl;
 
-       tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
+       tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
 
        iommu_table_getparms(dn, tbl);
 
        /* Look for existing tce table */
        dn->iommu_table = iommu_table_find(tbl);
-
        if (dn->iommu_table == NULL)
                dn->iommu_table = iommu_init_table(tbl);
        else
                kfree(tbl);
-
-       return;
 }
 
 
index fe6d636..f831d25 100644 (file)
@@ -110,6 +110,7 @@ static unsigned int iSeries_startup_IRQ(unsigned int irq)
        /* Unmask bridge interrupts in the FISR */
        mask = 0x01010000 << function;
        HvCallPci_unmaskFisr(bus, subBus, deviceId, mask);
+       iSeries_enable_IRQ(irq);
        return 0;
 }
 
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();
+}
+
index b70a924..6757952 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * arch/ppc64/kernel/iomap.c
+ *
+ * ppc64 "iomap" interface implementation.
+ *
+ * (C) Copyright 2004 Linus Torvalds
+ */
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/mm.h>
index 56a26ee..56d7ba8 100644 (file)
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 #include <asm/types.h>
 #include <asm/page.h>
 #include <asm/prom.h>
 #include <asm/lmb.h>
 #include <asm/abs_addr.h>
-#include <asm/bitops.h>
 
 struct lmb lmb;
 
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();
+}
index 02a68b1..1bd52ec 100644 (file)
@@ -1,6 +1,7 @@
 /*
   * mf.c
   * Copyright (C) 2001 Troy D. Armstrong  IBM Corporation
+  * Copyright (C) 2004 Stephen Rothwell  IBM Corporation
   *
   * This modules exists as an interface between a Linux secondary partition
   * running on an iSeries and the primary partition's Virtual Service
@@ -8,52 +9,44 @@
   * all partitions in the iSeries.  It also provides miscellaneous low-level
   * machine facility type operations.
   *
-  * 
+  *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the 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/iSeries/mf.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
 #include <linux/completion.h>
-#include <asm/iSeries/HvLpConfig.h>
-#include <linux/slab.h>
 #include <linux/delay.h>
-#include <asm/nvram.h>
-#include <asm/time.h>
-#include <asm/iSeries/ItSpCommArea.h>
-#include <asm/uaccess.h>
 #include <linux/dma-mapping.h>
 #include <linux/bcd.h>
+
+#include <asm/time.h>
+#include <asm/uaccess.h>
 #include <asm/iSeries/vio.h>
+#include <asm/iSeries/mf.h>
+#include <asm/iSeries/HvLpConfig.h>
+#include <asm/iSeries/ItSpCommArea.h>
 
 /*
  * This is the structure layout for the Machine Facilites LPAR event
  * flows.
  */
-union safe_cast {
-       u64 ptr_as_u64;
-       void *ptr;
-};
-
-struct VspCmdData {
-       union safe_cast token;
+struct vsp_cmd_data {
+       u64 token;
        u16 cmd;
        HvLpIndex lp_index;
        u8 result_code;
@@ -81,12 +74,12 @@ struct VspCmdData {
        } sub_data;
 };
 
-struct VspRspData {
+struct vsp_rsp_data {
        struct completion com;
-       struct VspCmdData *response;
+       struct vsp_cmd_data *response;
 };
 
-struct AllocData {
+struct alloc_data {
        u16 size;
        u16 type;
        u32 count;
@@ -95,30 +88,30 @@ struct AllocData {
        HvLpIndex target_lp;
 };
 
-struct CeMsgData;
+struct ce_msg_data;
 
-typedef void (*CeMsgCompleteHandler)(void *token, struct CeMsgData *vspCmdRsp);
+typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp);
 
-struct CeMsgCompleteData {
-       CeMsgCompleteHandler handler;
+struct ce_msg_comp_data {
+       ce_msg_comp_hdlr handler;
        void *token;
 };
 
-struct CeMsgData {
+struct ce_msg_data {
        u8 ce_msg[12];
        char reserved[4];
-       struct CeMsgCompleteData *completion;
+       struct ce_msg_comp_data *completion;
 };
 
-struct IoMFLpEvent {
+struct io_mf_lp_event {
        struct HvLpEvent hp_lp_event;
        u16 subtype_result_code;
        u16 reserved1;
        u32 reserved2;
        union {
-               struct AllocData alloc;
-               struct CeMsgData ce_msg;
-               struct VspCmdData vsp_cmd;
+               struct alloc_data alloc;
+               struct ce_msg_data ce_msg;
+               struct vsp_cmd_data vsp_cmd;
        } data;
 };
 
@@ -134,7 +127,7 @@ struct IoMFLpEvent {
  */
 struct pending_event {
        struct pending_event *next;
-       struct IoMFLpEvent event;
+       struct io_mf_lp_event event;
        MFCompleteHandler hdlr;
        char dma_data[72];
        unsigned dma_data_length;
@@ -172,7 +165,7 @@ static int signal_event(struct pending_event *ev)
        unsigned long flags;
        int go = 1;
        struct pending_event *ev1;
-       HvLpEvent_Rc hvRc;
+       HvLpEvent_Rc hv_rc;
 
        /* enqueue the event */
        if (ev != NULL) {
@@ -199,11 +192,11 @@ static int signal_event(struct pending_event *ev)
                                        pending_event_head->dma_data_length,
                                        HvLpDma_Direction_LocalToRemote);
 
-               hvRc = HvCallEvent_signalLpEvent(
+               hv_rc = HvCallEvent_signalLpEvent(
                                &pending_event_head->event.hp_lp_event);
-               if (hvRc != HvLpEvent_Rc_Good) {
-                       printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() failed with %d\n",
-                                       (int)hvRc);
+               if (hv_rc != HvLpEvent_Rc_Good) {
+                       printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() "
+                                       "failed with %d\n", (int)hv_rc);
 
                        spin_lock_irqsave(&pending_event_spinlock, flags);
                        ev1 = pending_event_head;
@@ -214,12 +207,8 @@ static int signal_event(struct pending_event *ev)
 
                        if (ev1 == ev)
                                rc = -EIO;
-                       else if (ev1->hdlr != NULL) {
-                               union safe_cast mySafeCast;
-
-                               mySafeCast.ptr_as_u64 = ev1->event.hp_lp_event.xCorrelationToken;
-                               (*ev1->hdlr)(mySafeCast.ptr, -EIO);
-                       }
+                       else if (ev1->hdlr != NULL)
+                               (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO);
 
                        spin_lock_irqsave(&pending_event_spinlock, flags);
                        free_pending_event(ev1);
@@ -236,7 +225,7 @@ static int signal_event(struct pending_event *ev)
 static struct pending_event *new_pending_event(void)
 {
        struct pending_event *ev = NULL;
-       HvLpIndex primaryLp = HvLpConfig_getPrimaryLpIndex();
+       HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex();
        unsigned long flags;
        struct HvLpEvent *hev;
 
@@ -246,12 +235,13 @@ static struct pending_event *new_pending_event(void)
                pending_event_avail = pending_event_avail->next;
        }
        spin_unlock_irqrestore(&pending_event_spinlock, flags);
-       if (ev == NULL)
-               ev = kmalloc(sizeof(struct pending_event),GFP_ATOMIC);
        if (ev == NULL) {
-               printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n",
-                               sizeof(struct pending_event));
-               return NULL;
+               ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC);
+               if (ev == NULL) {
+                       printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n",
+                                       sizeof(struct pending_event));
+                       return NULL;
+               }
        }
        memset(ev, 0, sizeof(struct pending_event));
        hev = &ev->event.hp_lp_event;
@@ -261,38 +251,38 @@ static struct pending_event *new_pending_event(void)
        hev->xFlags.xFunction = HvLpEvent_Function_Int;
        hev->xType = HvLpEvent_Type_MachineFac;
        hev->xSourceLp = HvLpConfig_getLpIndex();
-       hev->xTargetLp = primaryLp;
-       hev->xSizeMinus1 = sizeof(ev->event)-1;
+       hev->xTargetLp = primary_lp;
+       hev->xSizeMinus1 = sizeof(ev->event) - 1;
        hev->xRc = HvLpEvent_Rc_Good;
-       hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primaryLp,
+       hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp,
                        HvLpEvent_Type_MachineFac);
-       hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primaryLp,
+       hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp,
                        HvLpEvent_Type_MachineFac);
 
        return ev;
 }
 
-static int signal_vsp_instruction(struct VspCmdData *vspCmd)
+static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
-       struct VspRspData response;
+       struct vsp_rsp_data response;
 
        if (ev == NULL)
                return -ENOMEM;
 
        init_completion(&response.com);
-       response.response = vspCmd;
+       response.response = vsp_cmd;
        ev->event.hp_lp_event.xSubtype = 6;
        ev->event.hp_lp_event.x.xSubtypeData =
                subtype_data('M', 'F',  'V',  'I');
-       ev->event.data.vsp_cmd.token.ptr = &response;
-       ev->event.data.vsp_cmd.cmd = vspCmd->cmd;
+       ev->event.data.vsp_cmd.token = (u64)&response;
+       ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd;
        ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
        ev->event.data.vsp_cmd.result_code = 0xFF;
        ev->event.data.vsp_cmd.reserved = 0;
        memcpy(&(ev->event.data.vsp_cmd.sub_data),
-                       &(vspCmd->sub_data), sizeof(vspCmd->sub_data));
+                       &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data));
        mb();
 
        rc = signal_event(ev);
@@ -305,7 +295,7 @@ static int signal_vsp_instruction(struct VspCmdData *vspCmd)
 /*
  * Send a 12-byte CE message to the primary partition VSP object
  */
-static int signal_ce_msg(char *ce_msg, struct CeMsgCompleteData *completion)
+static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion)
 {
        struct pending_event *ev = new_pending_event();
 
@@ -320,11 +310,23 @@ static int signal_ce_msg(char *ce_msg, struct CeMsgCompleteData *completion)
        return signal_event(ev);
 }
 
+/*
+ * Send a 12-byte CE message (with no data) to the primary partition VSP object
+ */
+static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion)
+{
+       u8 ce_msg[12];
+
+       memset(ce_msg, 0, sizeof(ce_msg));
+       ce_msg[3] = ce_op;
+       return signal_ce_msg(ce_msg, completion);
+}
+
 /*
  * Send a 12-byte CE message and DMA data to the primary partition VSP object
  */
 static int dma_and_signal_ce_msg(char *ce_msg,
-               struct CeMsgCompleteData *completion, void *dma_data,
+               struct ce_msg_comp_data *completion, void *dma_data,
                unsigned dma_data_length, unsigned remote_address)
 {
        struct pending_event *ev = new_pending_event();
@@ -356,7 +358,7 @@ static int shutdown(void)
        if (rc) {
                printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "
                                "hard shutdown commencing\n", rc);
-               mf_powerOff();
+               mf_power_off();
        } else
                printk(KERN_INFO "mf.c: init has been successfully notified "
                                "to proceed with shutdown\n");
@@ -367,10 +369,12 @@ static int shutdown(void)
  * The primary partition VSP object is sending us a new
  * event flow.  Handle it...
  */
-static void intReceived(struct IoMFLpEvent *event)
+static void handle_int(struct io_mf_lp_event *event)
 {
-       int freeIt = 0;
-       struct pending_event *two = NULL;
+       struct ce_msg_data *ce_msg_data;
+       struct ce_msg_data *pce_msg_data;
+       unsigned long flags;
+       struct pending_event *pev;
 
        /* ack the interrupt */
        event->hp_lp_event.xRc = HvLpEvent_Rc_Good;
@@ -379,49 +383,42 @@ static void intReceived(struct IoMFLpEvent *event)
        /* process interrupt */
        switch (event->hp_lp_event.xSubtype) {
        case 0: /* CE message */
-               switch (event->data.ce_msg.ce_msg[3]) {
+               ce_msg_data = &event->data.ce_msg;
+               switch (ce_msg_data->ce_msg[3]) {
                case 0x5B:      /* power control notification */
-                       if ((event->data.ce_msg.ce_msg[5] & 0x20) != 0) {
+                       if ((ce_msg_data->ce_msg[5] & 0x20) != 0) {
                                printk(KERN_INFO "mf.c: Commencing partition shutdown\n");
                                if (shutdown() == 0)
-                                       signal_ce_msg("\x00\x00\x00\xDB\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
+                                       signal_ce_msg_simple(0xDB, NULL);
                        }
                        break;
                case 0xC0:      /* get time */
-                       if ((pending_event_head == NULL) ||
-                           (pending_event_head->event.data.ce_msg.ce_msg[3]
-                            != 0x40))
+                       spin_lock_irqsave(&pending_event_spinlock, flags);
+                       pev = pending_event_head;
+                       if (pev != NULL)
+                               pending_event_head = pending_event_head->next;
+                       spin_unlock_irqrestore(&pending_event_spinlock, flags);
+                       if (pev == NULL)
                                break;
-                       freeIt = 1;
-                       if (pending_event_head->event.data.ce_msg.completion != 0) {
-                               CeMsgCompleteHandler handler = pending_event_head->event.data.ce_msg.completion->handler;
-                               void *token = pending_event_head->event.data.ce_msg.completion->token;
+                       pce_msg_data = &pev->event.data.ce_msg;
+                       if (pce_msg_data->ce_msg[3] != 0x40)
+                               break;
+                       if (pce_msg_data->completion != NULL) {
+                               ce_msg_comp_hdlr handler =
+                                       pce_msg_data->completion->handler;
+                               void *token = pce_msg_data->completion->token;
 
                                if (handler != NULL)
-                                       (*handler)(token, &(event->data.ce_msg));
+                                       (*handler)(token, ce_msg_data);
                        }
-                       break;
-               }
-
-               /* remove from queue */
-               if (freeIt == 1) {
-                       unsigned long flags;
-
                        spin_lock_irqsave(&pending_event_spinlock, flags);
-                       if (pending_event_head != NULL) {
-                               struct pending_event *oldHead =
-                                       pending_event_head;
-
-                               pending_event_head = pending_event_head->next;
-                               two = pending_event_head;
-                               free_pending_event(oldHead);
-                       }
+                       free_pending_event(pev);
                        spin_unlock_irqrestore(&pending_event_spinlock, flags);
+                       /* send next waiting event */
+                       if (pending_event_head != NULL)
+                               signal_event(NULL);
+                       break;
                }
-
-               /* send next waiting event */
-               if (two != NULL)
-                       signal_event(NULL);
                break;
        case 1: /* IT sys shutdown */
                printk(KERN_INFO "mf.c: Commencing system shutdown\n");
@@ -435,68 +432,70 @@ static void intReceived(struct IoMFLpEvent *event)
  * of a flow we sent to them.  If there are other flows queued
  * up, we must send another one now...
  */
-static void ackReceived(struct IoMFLpEvent *event)
+static void handle_ack(struct io_mf_lp_event *event)
 {
        unsigned long flags;
-       struct pending_event * two = NULL;
-       unsigned long freeIt = 0;
+       struct pending_event *two = NULL;
+       unsigned long free_it = 0;
+       struct ce_msg_data *ce_msg_data;
+       struct ce_msg_data *pce_msg_data;
+       struct vsp_rsp_data *rsp;
 
        /* handle current event */
-       if (pending_event_head != NULL) {
-               switch (event->hp_lp_event.xSubtype) {
-               case 0:     /* CE msg */
-                       if (event->data.ce_msg.ce_msg[3] == 0x40) {
-                               if (event->data.ce_msg.ce_msg[2] != 0) {
-                                       freeIt = 1;
-                                       if (pending_event_head->event.data.ce_msg.completion
-                                                       != 0) {
-                                               CeMsgCompleteHandler handler = pending_event_head->event.data.ce_msg.completion->handler;
-                                               void *token = pending_event_head->event.data.ce_msg.completion->token;
-
-                                               if (handler != NULL)
-                                                       (*handler)(token, &(event->data.ce_msg));
-                                       }
-                               }
-                       } else
-                               freeIt = 1;
-                       break;
-               case 4: /* allocate */
-               case 5: /* deallocate */
-                       if (pending_event_head->hdlr != NULL) {
-                               union safe_cast mySafeCast;
+       if (pending_event_head == NULL) {
+               printk(KERN_ERR "mf.c: stack empty for receiving ack\n");
+               return;
+       }
 
-                               mySafeCast.ptr_as_u64 = event->hp_lp_event.xCorrelationToken;
-                               (*pending_event_head->hdlr)(mySafeCast.ptr, event->data.alloc.count);
-                       }
-                       freeIt = 1;
+       switch (event->hp_lp_event.xSubtype) {
+       case 0:     /* CE msg */
+               ce_msg_data = &event->data.ce_msg;
+               if (ce_msg_data->ce_msg[3] != 0x40) {
+                       free_it = 1;
                        break;
-               case 6:
-                       {
-                               struct VspRspData *rsp = (struct VspRspData *)event->data.vsp_cmd.token.ptr;
-
-                               if (rsp != NULL) {
-                                       if (rsp->response != NULL)
-                                               memcpy(rsp->response, &(event->data.vsp_cmd), sizeof(event->data.vsp_cmd));
-                                       complete(&rsp->com);
-                               } else
-                                       printk(KERN_ERR "mf.c: no rsp\n");
-                               freeIt = 1;
-                       }
+               }
+               if (ce_msg_data->ce_msg[2] == 0)
+                       break;
+               free_it = 1;
+               pce_msg_data = &pending_event_head->event.data.ce_msg;
+               if (pce_msg_data->completion != NULL) {
+                       ce_msg_comp_hdlr handler =
+                               pce_msg_data->completion->handler;
+                       void *token = pce_msg_data->completion->token;
+
+                       if (handler != NULL)
+                               (*handler)(token, ce_msg_data);
+               }
+               break;
+       case 4: /* allocate */
+       case 5: /* deallocate */
+               if (pending_event_head->hdlr != NULL)
+                       (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count);
+               free_it = 1;
+               break;
+       case 6:
+               free_it = 1;
+               rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token;
+               if (rsp == NULL) {
+                       printk(KERN_ERR "mf.c: no rsp\n");
                        break;
                }
+               if (rsp->response != NULL)
+                       memcpy(rsp->response, &event->data.vsp_cmd,
+                                       sizeof(event->data.vsp_cmd));
+               complete(&rsp->com);
+               break;
        }
-       else
-               printk(KERN_ERR "mf.c: stack empty for receiving ack\n");
 
        /* remove from queue */
        spin_lock_irqsave(&pending_event_spinlock, flags);
-       if ((pending_event_head != NULL) && (freeIt == 1)) {
+       if ((pending_event_head != NULL) && (free_it == 1)) {
                struct pending_event *oldHead = pending_event_head;
 
                pending_event_head = pending_event_head->next;
                two = pending_event_head;
                free_pending_event(oldHead);
-       } 
+       }
        spin_unlock_irqrestore(&pending_event_spinlock, flags);
 
        /* send next waiting event */
@@ -510,15 +509,15 @@ static void ackReceived(struct IoMFLpEvent *event)
  * parse it enough to know if it is an interrupt or an
  * acknowledge.
  */
-static void hvHandler(struct HvLpEvent *event, struct pt_regs *regs)
+static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs)
 {
        if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {
                switch(event->xFlags.xFunction) {
                case HvLpEvent_Function_Ack:
-                       ackReceived((struct IoMFLpEvent *)event);
+                       handle_ack((struct io_mf_lp_event *)event);
                        break;
                case HvLpEvent_Function_Int:
-                       intReceived((struct IoMFLpEvent *)event);
+                       handle_int((struct io_mf_lp_event *)event);
                        break;
                default:
                        printk(KERN_ERR "mf.c: non ack/int event received\n");
@@ -532,9 +531,9 @@ static void hvHandler(struct HvLpEvent *event, struct pt_regs *regs)
  * Global kernel interface to allocate and seed events into the
  * Hypervisor.
  */
-void mf_allocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
+void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
                unsigned size, unsigned count, MFCompleteHandler hdlr,
-               void *userToken)
+               void *user_token)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
@@ -542,14 +541,11 @@ void mf_allocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
        if (ev == NULL) {
                rc = -ENOMEM;
        } else {
-               union safe_cast mine;
-
-               mine.ptr = userToken;
                ev->event.hp_lp_event.xSubtype = 4;
-               ev->event.hp_lp_event.xCorrelationToken = mine.ptr_as_u64;
+               ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
                ev->event.hp_lp_event.x.xSubtypeData =
                        subtype_data('M', 'F', 'M', 'A');
-               ev->event.data.alloc.target_lp = targetLp;
+               ev->event.data.alloc.target_lp = target_lp;
                ev->event.data.alloc.type = type;
                ev->event.data.alloc.size = size;
                ev->event.data.alloc.count = count;
@@ -557,16 +553,16 @@ void mf_allocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
                rc = signal_event(ev);
        }
        if ((rc != 0) && (hdlr != NULL))
-               (*hdlr)(userToken, rc);
+               (*hdlr)(user_token, rc);
 }
-EXPORT_SYMBOL(mf_allocateLpEvents);
+EXPORT_SYMBOL(mf_allocate_lp_events);
 
 /*
  * Global kernel interface to unseed and deallocate events already in
  * Hypervisor.
  */
-void mf_deallocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
-               unsigned count, MFCompleteHandler hdlr, void *userToken)
+void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
+               unsigned count, MFCompleteHandler hdlr, void *user_token)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
@@ -574,33 +570,31 @@ void mf_deallocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
        if (ev == NULL)
                rc = -ENOMEM;
        else {
-               union safe_cast mine;
-
-               mine.ptr = userToken;
                ev->event.hp_lp_event.xSubtype = 5;
-               ev->event.hp_lp_event.xCorrelationToken = mine.ptr_as_u64;
+               ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
                ev->event.hp_lp_event.x.xSubtypeData =
                        subtype_data('M', 'F', 'M', 'D');
-               ev->event.data.alloc.target_lp = targetLp;
+               ev->event.data.alloc.target_lp = target_lp;
                ev->event.data.alloc.type = type;
                ev->event.data.alloc.count = count;
                ev->hdlr = hdlr;
                rc = signal_event(ev);
        }
        if ((rc != 0) && (hdlr != NULL))
-               (*hdlr)(userToken, rc);
+               (*hdlr)(user_token, rc);
 }
-EXPORT_SYMBOL(mf_deallocateLpEvents);
+EXPORT_SYMBOL(mf_deallocate_lp_events);
 
 /*
  * Global kernel interface to tell the VSP object in the primary
  * partition to power this partition off.
  */
-void mf_powerOff(void)
+void mf_power_off(void)
 {
        printk(KERN_INFO "mf.c: Down it goes...\n");
-       signal_ce_msg("\x00\x00\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
-       for (;;);
+       signal_ce_msg_simple(0x4d, NULL);
+       for (;;)
+               ;
 }
 
 /*
@@ -610,18 +604,21 @@ void mf_powerOff(void)
 void mf_reboot(void)
 {
        printk(KERN_INFO "mf.c: Preparing to bounce...\n");
-       signal_ce_msg("\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
-       for (;;);
+       signal_ce_msg_simple(0x4e, NULL);
+       for (;;)
+               ;
 }
 
 /*
  * Display a single word SRC onto the VSP control panel.
  */
-void mf_displaySrc(u32 word)
+void mf_display_src(u32 word)
 {
        u8 ce[12];
 
-       memcpy(ce, "\x00\x00\x00\x4A\x00\x00\x00\x01\x00\x00\x00\x00", 12);
+       memset(ce, 0, sizeof(ce));
+       ce[3] = 0x4a;
+       ce[7] = 0x01;
        ce[8] = word >> 24;
        ce[9] = word >> 16;
        ce[10] = word >> 8;
@@ -632,7 +629,7 @@ void mf_displaySrc(u32 word)
 /*
  * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.
  */
-void mf_displayProgress(u16 value)
+void mf_display_progress(u16 value)
 {
        u8 ce[12];
        u8 src[72];
@@ -656,9 +653,9 @@ void mf_displayProgress(u16 value)
  * Clear the VSP control panel.  Used to "erase" an SRC that was
  * previously displayed.
  */
-void mf_clearSrc(void)
+void mf_clear_src(void)
 {
-       signal_ce_msg("\x00\x00\x00\x4B\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
+       signal_ce_msg_simple(0x4b, NULL);
 }
 
 /*
@@ -674,71 +671,331 @@ void mf_init(void)
             i < sizeof(pending_event_prealloc) / sizeof(*pending_event_prealloc);
             ++i)
                free_pending_event(&pending_event_prealloc[i]);
-       HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hvHandler);
+       HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler);
 
        /* virtual continue ack */
-       signal_ce_msg("\x00\x00\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
+       signal_ce_msg_simple(0x57, NULL);
 
        /* initialization complete */
-       printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n");
+       printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities "
+                       "initialized\n");
 }
 
-void mf_setSide(char side)
+struct rtc_time_data {
+       struct completion com;
+       struct ce_msg_data ce_msg;
+       int rc;
+};
+
+static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
 {
-       u64 newSide;
-       struct VspCmdData myVspCmd;
+       struct rtc_time_data *rtc = token;
 
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       switch (side) {
-       case 'A':       newSide = 0;
-                       break;
-       case 'B':       newSide = 1;
-                       break;
-       case 'C':       newSide = 2; 
-                       break;
-       default:        newSide = 3;
+       memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
+       rtc->rc = 0;
+       complete(&rtc->com);
+}
+
+int mf_get_rtc(struct rtc_time *tm)
+{
+       struct ce_msg_comp_data ce_complete;
+       struct rtc_time_data rtc_data;
+       int rc;
+
+       memset(&ce_complete, 0, sizeof(ce_complete));
+       memset(&rtc_data, 0, sizeof(rtc_data));
+       init_completion(&rtc_data.com);
+       ce_complete.handler = &get_rtc_time_complete;
+       ce_complete.token = &rtc_data;
+       rc = signal_ce_msg_simple(0x40, &ce_complete);
+       if (rc)
+               return rc;
+       wait_for_completion(&rtc_data.com);
+       tm->tm_wday = 0;
+       tm->tm_yday = 0;
+       tm->tm_isdst = 0;
+       if (rtc_data.rc) {
+               tm->tm_sec = 0;
+               tm->tm_min = 0;
+               tm->tm_hour = 0;
+               tm->tm_mday = 15;
+               tm->tm_mon = 5;
+               tm->tm_year = 52;
+               return rtc_data.rc;
+       }
+
+       if ((rtc_data.ce_msg.ce_msg[2] == 0xa9) ||
+           (rtc_data.ce_msg.ce_msg[2] == 0xaf)) {
+               /* TOD clock is not set */
+               tm->tm_sec = 1;
+               tm->tm_min = 1;
+               tm->tm_hour = 1;
+               tm->tm_mday = 10;
+               tm->tm_mon = 8;
+               tm->tm_year = 71;
+               mf_set_rtc(tm);
+       }
+       {
+               u8 *ce_msg = rtc_data.ce_msg.ce_msg;
+               u8 year = ce_msg[5];
+               u8 sec = ce_msg[6];
+               u8 min = ce_msg[7];
+               u8 hour = ce_msg[8];
+               u8 day = ce_msg[10];
+               u8 mon = ce_msg[11];
+
+               BCD_TO_BIN(sec);
+               BCD_TO_BIN(min);
+               BCD_TO_BIN(hour);
+               BCD_TO_BIN(day);
+               BCD_TO_BIN(mon);
+               BCD_TO_BIN(year);
+
+               if (year <= 69)
+                       year += 100;
+
+               tm->tm_sec = sec;
+               tm->tm_min = min;
+               tm->tm_hour = hour;
+               tm->tm_mday = day;
+               tm->tm_mon = mon;
+               tm->tm_year = year;
+       }
+
+       return 0;
+}
+
+int mf_set_rtc(struct rtc_time *tm)
+{
+       char ce_time[12];
+       u8 day, mon, hour, min, sec, y1, y2;
+       unsigned year;
+
+       year = 1900 + tm->tm_year;
+       y1 = year / 100;
+       y2 = year % 100;
+
+       sec = tm->tm_sec;
+       min = tm->tm_min;
+       hour = tm->tm_hour;
+       day = tm->tm_mday;
+       mon = tm->tm_mon + 1;
+
+       BIN_TO_BCD(sec);
+       BIN_TO_BCD(min);
+       BIN_TO_BCD(hour);
+       BIN_TO_BCD(mon);
+       BIN_TO_BCD(day);
+       BIN_TO_BCD(y1);
+       BIN_TO_BCD(y2);
+
+       memset(ce_time, 0, sizeof(ce_time));
+       ce_time[3] = 0x41;
+       ce_time[4] = y1;
+       ce_time[5] = y2;
+       ce_time[6] = sec;
+       ce_time[7] = min;
+       ce_time[8] = hour;
+       ce_time[10] = day;
+       ce_time[11] = mon;
+
+       return signal_ce_msg(ce_time, NULL);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       int len;
+       char *p;
+       struct vsp_cmd_data vsp_cmd;
+       int rc;
+       dma_addr_t dma_addr;
+
+       /* The HV appears to return no more than 256 bytes of command line */
+       if (off >= 256)
+               return 0;
+       if ((off + count) > 256)
+               count = 256 - off;
+
+       dma_addr = dma_map_single(iSeries_vio_dev, page, off + count,
+                       DMA_FROM_DEVICE);
+       if (dma_mapping_error(dma_addr))
+               return -ENOMEM;
+       memset(page, 0, off + count);
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 33;
+       vsp_cmd.sub_data.kern.token = dma_addr;
+       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
+       vsp_cmd.sub_data.kern.side = (u64)data;
+       vsp_cmd.sub_data.kern.length = off + count;
+       mb();
+       rc = signal_vsp_instruction(&vsp_cmd);
+       dma_unmap_single(iSeries_vio_dev, dma_addr, off + count,
+                       DMA_FROM_DEVICE);
+       if (rc)
+               return rc;
+       if (vsp_cmd.result_code != 0)
+               return -ENOMEM;
+       p = page;
+       len = 0;
+       while (len < (off + count)) {
+               if ((*p == '\0') || (*p == '\n')) {
+                       if (*p == '\0')
+                               *p = '\n';
+                       p++;
+                       len++;
+                       *eof = 1;
                        break;
+               }
+               p++;
+               len++;
        }
-       myVspCmd.sub_data.ipl_type = newSide;
-       myVspCmd.cmd = 10;
 
-       (void)signal_vsp_instruction(&myVspCmd);
+       if (len < off) {
+               *eof = 1;
+               len = 0;
+       }
+       return len;
 }
 
-char mf_getSide(void)
+#if 0
+static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
 {
-       char returnValue = ' ';
-       int rc = 0;
-       struct VspCmdData myVspCmd;
+       struct vsp_cmd_data vsp_cmd;
+       int rc;
+       int len = *size;
+       dma_addr_t dma_addr;
+
+       dma_addr = dma_map_single(iSeries_vio_dev, buffer, len,
+                       DMA_FROM_DEVICE);
+       memset(buffer, 0, len);
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 32;
+       vsp_cmd.sub_data.kern.token = dma_addr;
+       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
+       vsp_cmd.sub_data.kern.side = side;
+       vsp_cmd.sub_data.kern.offset = offset;
+       vsp_cmd.sub_data.kern.length = len;
+       mb();
+       rc = signal_vsp_instruction(&vsp_cmd);
+       if (rc == 0) {
+               if (vsp_cmd.result_code == 0)
+                       *size = vsp_cmd.sub_data.length_out;
+               else
+                       rc = -ENOMEM;
+       }
+
+       dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE);
+
+       return rc;
+}
+
+static int proc_mf_dump_vmlinux(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       int sizeToGet = count;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) {
+               if (sizeToGet != 0) {
+                       *start = page + off;
+                       return sizeToGet;
+               }
+               *eof = 1;
+               return 0;
+       }
+       *eof = 1;
+       return 0;
+}
+#endif
+
+static int proc_mf_dump_side(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       int len;
+       char mf_current_side = ' ';
+       struct vsp_cmd_data vsp_cmd;
 
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       myVspCmd.cmd = 2;
-       myVspCmd.sub_data.ipl_type = 0;
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 2;
+       vsp_cmd.sub_data.ipl_type = 0;
        mb();
-       rc = signal_vsp_instruction(&myVspCmd);
 
-       if (rc != 0)
-               return returnValue;
+       if (signal_vsp_instruction(&vsp_cmd) == 0) {
+               if (vsp_cmd.result_code == 0) {
+                       switch (vsp_cmd.sub_data.ipl_type) {
+                       case 0: mf_current_side = 'A';
+                               break;
+                       case 1: mf_current_side = 'B';
+                               break;
+                       case 2: mf_current_side = 'C';
+                               break;
+                       default:        mf_current_side = 'D';
+                               break;
+                       }
+               }
+       }
+
+       len = sprintf(page, "%c\n", mf_current_side);
+
+       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 proc_mf_change_side(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+       char side;
+       u64 newSide;
+       struct vsp_cmd_data vsp_cmd;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
 
-       if (myVspCmd.result_code == 0) {
-               switch (myVspCmd.sub_data.ipl_type) {
-               case 0: returnValue = 'A';
+       if (count == 0)
+               return 0;
+
+       if (get_user(side, buffer))
+               return -EFAULT;
+
+       switch (side) {
+       case 'A':       newSide = 0;
                        break;
-               case 1: returnValue = 'B';
+       case 'B':       newSide = 1;
                        break;
-               case 2: returnValue = 'C';
+       case 'C':       newSide = 2;
                        break;
-               default:        returnValue = 'D';
+       case 'D':       newSide = 3;
                        break;
-               }
+       default:
+               printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
+               return -EINVAL;
        }
-       return returnValue;
+
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.sub_data.ipl_type = newSide;
+       vsp_cmd.cmd = 10;
+
+       (void)signal_vsp_instruction(&vsp_cmd);
+
+       return count;
 }
 
-void mf_getSrcHistory(char *buffer, int size)
-{
 #if 0
-       struct IplTypeReturnStuff returnStuff;
+static void mf_getSrcHistory(char *buffer, int size)
+{
+       struct IplTypeReturnStuff return_stuff;
        struct pending_event *ev = new_pending_event();
        int rc = 0;
        char *pages[4];
@@ -751,13 +1008,13 @@ void mf_getSrcHistory(char *buffer, int size)
                         || (pages[2] == NULL) || (pages[3] == NULL))
                return -ENOMEM;
 
-       returnStuff.xType = 0;
-       returnStuff.xRc = 0;
-       returnStuff.xDone = 0;
+       return_stuff.xType = 0;
+       return_stuff.xRc = 0;
+       return_stuff.xDone = 0;
        ev->event.hp_lp_event.xSubtype = 6;
        ev->event.hp_lp_event.x.xSubtypeData =
                subtype_data('M', 'F', 'V', 'I');
-       ev->event.data.vsp_cmd.xEvent = &returnStuff;
+       ev->event.data.vsp_cmd.xEvent = &return_stuff;
        ev->event.data.vsp_cmd.cmd = 4;
        ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
        ev->event.data.vsp_cmd.result_code = 0xFF;
@@ -770,312 +1027,213 @@ void mf_getSrcHistory(char *buffer, int size)
        if (signal_event(ev) != 0)
                return;
 
-       while (returnStuff.xDone != 1)
+       while (return_stuff.xDone != 1)
                udelay(10);
-       if (returnStuff.xRc == 0)
+       if (return_stuff.xRc == 0)
                memcpy(buffer, pages[0], size);
        kfree(pages[0]);
        kfree(pages[1]);
        kfree(pages[2]);
        kfree(pages[3]);
-#endif
-}
-
-void mf_setCmdLine(const char *cmdline, int size, u64 side)
-{
-       struct VspCmdData myVspCmd;
-       dma_addr_t dma_addr = 0;
-       char *page = dma_alloc_coherent(iSeries_vio_dev, size, &dma_addr,
-                       GFP_ATOMIC);
-
-       if (page == NULL) {
-               printk(KERN_ERR "mf.c: couldn't allocate memory to set command line\n");
-               return;
-       }
-
-       copy_from_user(page, cmdline, size);
-
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       myVspCmd.cmd = 31;
-       myVspCmd.sub_data.kern.token = dma_addr;
-       myVspCmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       myVspCmd.sub_data.kern.side = side;
-       myVspCmd.sub_data.kern.length = size;
-       mb();
-       (void)signal_vsp_instruction(&myVspCmd);
-
-       dma_free_coherent(iSeries_vio_dev, size, page, dma_addr);
 }
+#endif
 
-int mf_getCmdLine(char *cmdline, int *size, u64 side)
+static int proc_mf_dump_src(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
 {
-       struct VspCmdData myVspCmd;
-       int rc;
-       int len = *size;
-       dma_addr_t dma_addr;
-
-       dma_addr = dma_map_single(iSeries_vio_dev, cmdline, len,
-                       DMA_FROM_DEVICE);
-       memset(cmdline, 0, len);
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       myVspCmd.cmd = 33;
-       myVspCmd.sub_data.kern.token = dma_addr;
-       myVspCmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       myVspCmd.sub_data.kern.side = side;
-       myVspCmd.sub_data.kern.length = len;
-       mb();
-       rc = signal_vsp_instruction(&myVspCmd);
-
-       if (rc == 0) {
-               if (myVspCmd.result_code == 0)
-                       len = myVspCmd.sub_data.length_out;
 #if 0
-               else
-                       memcpy(cmdline, "Bad cmdline", 11);
-#endif
-       }
-
-       dma_unmap_single(iSeries_vio_dev, dma_addr, *size, DMA_FROM_DEVICE);
-
+       int len;
+
+       mf_getSrcHistory(page, count);
+       len = count;
+       len -= off;
+       if (len < count) {
+               *eof = 1;
+               if (len <= 0)
+                       return 0;
+       } else
+               len = count;
+       *start = page + off;
        return len;
+#else
+       return 0;
+#endif
 }
 
-
-int mf_setVmlinuxChunk(const char *buffer, int size, int offset, u64 side)
+static int proc_mf_change_src(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
 {
-       struct VspCmdData myVspCmd;
-       int rc;
-       dma_addr_t dma_addr = 0;
-       char *page = dma_alloc_coherent(iSeries_vio_dev, size, &dma_addr,
-                       GFP_ATOMIC);
+       char stkbuf[10];
 
-       if (page == NULL) {
-               printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
-               return -ENOMEM;
-       }
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
 
-       copy_from_user(page, buffer, size);
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-
-       myVspCmd.cmd = 30;
-       myVspCmd.sub_data.kern.token = dma_addr;
-       myVspCmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       myVspCmd.sub_data.kern.side = side;
-       myVspCmd.sub_data.kern.offset = offset;
-       myVspCmd.sub_data.kern.length = size;
-       mb();
-       rc = signal_vsp_instruction(&myVspCmd);
-       if (rc == 0) {
-               if (myVspCmd.result_code == 0)
-                       rc = 0;
-               else
-                       rc = -ENOMEM;
+       if ((count < 4) && (count != 1)) {
+               printk(KERN_ERR "mf_proc: invalid src\n");
+               return -EINVAL;
        }
 
-       dma_free_coherent(iSeries_vio_dev, size, page, dma_addr);
+       if (count > (sizeof(stkbuf) - 1))
+               count = sizeof(stkbuf) - 1;
+       if (copy_from_user(stkbuf, buffer, count))
+               return -EFAULT;
 
-       return rc;
+       if ((count == 1) && (*stkbuf == '\0'))
+               mf_clear_src();
+       else
+               mf_display_src(*(u32 *)stkbuf);
+
+       return count;
 }
 
-int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
+static int proc_mf_change_cmdline(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
 {
-       struct VspCmdData myVspCmd;
-       int rc;
-       int len = *size;
+       struct vsp_cmd_data vsp_cmd;
        dma_addr_t dma_addr;
+       char *page;
+       int ret = -EACCES;
 
-       dma_addr = dma_map_single(iSeries_vio_dev, buffer, len,
-                       DMA_FROM_DEVICE);
-       memset(buffer, 0, len);
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       myVspCmd.cmd = 32;
-       myVspCmd.sub_data.kern.token = dma_addr;
-       myVspCmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       myVspCmd.sub_data.kern.side = side;
-       myVspCmd.sub_data.kern.offset = offset;
-       myVspCmd.sub_data.kern.length = len;
-       mb();
-       rc = signal_vsp_instruction(&myVspCmd);
-       if (rc == 0) {
-               if (myVspCmd.result_code == 0)
-                       *size = myVspCmd.sub_data.length_out;
-               else
-                       rc = -ENOMEM;
-       }
+       if (!capable(CAP_SYS_ADMIN))
+               goto out;
 
-       dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE);
+       dma_addr = 0;
+       page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr,
+                       GFP_ATOMIC);
+       ret = -ENOMEM;
+       if (page == NULL)
+               goto out;
+
+       ret = -EFAULT;
+       if (copy_from_user(page, buffer, count))
+               goto out_free;
+
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 31;
+       vsp_cmd.sub_data.kern.token = dma_addr;
+       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
+       vsp_cmd.sub_data.kern.side = (u64)data;
+       vsp_cmd.sub_data.kern.length = count;
+       mb();
+       (void)signal_vsp_instruction(&vsp_cmd);
+       ret = count;
 
-       return rc;
+out_free:
+       dma_free_coherent(iSeries_vio_dev, count, page, dma_addr);
+out:
+       return ret;
 }
 
-int mf_setRtcTime(unsigned long time)
+static ssize_t proc_mf_change_vmlinux(struct file *file,
+                                     const char __user *buf,
+                                     size_t count, loff_t *ppos)
 {
-       struct rtc_time tm;
+       struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+       ssize_t rc;
+       dma_addr_t dma_addr;
+       char *page;
+       struct vsp_cmd_data vsp_cmd;
 
-       to_tm(time, &tm);
+       rc = -EACCES;
+       if (!capable(CAP_SYS_ADMIN))
+               goto out;
 
-       return mf_setRtc(&tm);
+       dma_addr = 0;
+       page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr,
+                       GFP_ATOMIC);
+       rc = -ENOMEM;
+       if (page == NULL) {
+               printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
+               goto out;
+       }
+       rc = -EFAULT;
+       if (copy_from_user(page, buf, count))
+               goto out_free;
+
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 30;
+       vsp_cmd.sub_data.kern.token = dma_addr;
+       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
+       vsp_cmd.sub_data.kern.side = (u64)dp->data;
+       vsp_cmd.sub_data.kern.offset = *ppos;
+       vsp_cmd.sub_data.kern.length = count;
+       mb();
+       rc = signal_vsp_instruction(&vsp_cmd);
+       if (rc)
+               goto out_free;
+       rc = -ENOMEM;
+       if (vsp_cmd.result_code != 0)
+               goto out_free;
+
+       *ppos += count;
+       rc = count;
+out_free:
+       dma_free_coherent(iSeries_vio_dev, count, page, dma_addr);
+out:
+       return rc;
 }
 
-struct RtcTimeData {
-       struct completion com;
-       struct CeMsgData xCeMsg;
-       int xRc;
+static struct file_operations proc_vmlinux_operations = {
+       .write          = proc_mf_change_vmlinux,
 };
 
-void getRtcTimeComplete(void * token, struct CeMsgData *ceMsg)
+static int __init mf_proc_init(void)
 {
-       struct RtcTimeData *rtc = (struct RtcTimeData *)token;
-
-       memcpy(&(rtc->xCeMsg), ceMsg, sizeof(rtc->xCeMsg));
-       rtc->xRc = 0;
-       complete(&rtc->com);
-}
-
-static unsigned long lastsec = 1;
+       struct proc_dir_entry *mf_proc_root;
+       struct proc_dir_entry *ent;
+       struct proc_dir_entry *mf;
+       char name[2];
+       int i;
 
-int mf_getRtcTime(unsigned long *time)
-{
-       u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart));
-       u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1);
-       int year = 1970;
-       int year1 = (dataWord1 >> 24) & 0x000000FF;
-       int year2 = (dataWord1 >> 16) & 0x000000FF;
-       int sec = (dataWord1 >> 8) & 0x000000FF;
-       int min = dataWord1 & 0x000000FF;
-       int hour = (dataWord2 >> 24) & 0x000000FF;
-       int day = (dataWord2 >> 8) & 0x000000FF;
-       int mon = dataWord2 & 0x000000FF;
-
-       BCD_TO_BIN(sec);
-       BCD_TO_BIN(min);
-       BCD_TO_BIN(hour);
-       BCD_TO_BIN(day);
-       BCD_TO_BIN(mon);
-       BCD_TO_BIN(year1);
-       BCD_TO_BIN(year2);
-       year = year1 * 100 + year2;
-
-       *time = mktime(year, mon, day, hour, min, sec);
-       *time += (jiffies / HZ);
-    
-       /*
-        * Now THIS is a nasty hack!
-        * It ensures that the first two calls to mf_getRtcTime get different
-        * answers.  That way the loop in init_time (time.c) will not think
-        * the clock is stuck.
-        */
-       if (lastsec) {
-               *time -= lastsec;
-               --lastsec;
+       mf_proc_root = proc_mkdir("iSeries/mf", NULL);
+       if (!mf_proc_root)
+               return 1;
+
+       name[1] = '\0';
+       for (i = 0; i < 4; i++) {
+               name[0] = 'A' + i;
+               mf = proc_mkdir(name, mf_proc_root);
+               if (!mf)
+                       return 1;
+
+               ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf);
+               if (!ent)
+                       return 1;
+               ent->nlink = 1;
+               ent->data = (void *)(long)i;
+               ent->read_proc = proc_mf_dump_cmdline;
+               ent->write_proc = proc_mf_change_cmdline;
+
+               if (i == 3)     /* no vmlinux entry for 'D' */
+                       continue;
+
+               ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf);
+               if (!ent)
+                       return 1;
+               ent->nlink = 1;
+               ent->data = (void *)(long)i;
+               ent->proc_fops = &proc_vmlinux_operations;
        }
-       return 0;
-}
-
-int mf_getRtc(struct rtc_time *tm)
-{
-       struct CeMsgCompleteData ceComplete;
-       struct RtcTimeData rtcData;
-       int rc;
-
-       memset(&ceComplete, 0, sizeof(ceComplete));
-       memset(&rtcData, 0, sizeof(rtcData));
-       init_completion(&rtcData.com);
-       ceComplete.handler = &getRtcTimeComplete;
-       ceComplete.token = (void *)&rtcData;
-       rc = signal_ce_msg("\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00",
-                       &ceComplete);
-       if (rc == 0) {
-               wait_for_completion(&rtcData.com);
-
-               if (rtcData.xRc == 0) {
-                       if ((rtcData.xCeMsg.ce_msg[2] == 0xa9) ||
-                           (rtcData.xCeMsg.ce_msg[2] == 0xaf)) {
-                               /* TOD clock is not set */
-                               tm->tm_sec = 1;
-                               tm->tm_min = 1;
-                               tm->tm_hour = 1;
-                               tm->tm_mday = 10;
-                               tm->tm_mon = 8;
-                               tm->tm_year = 71;
-                               mf_setRtc(tm);
-                       }
-                       {
-                               u32 dataWord1 = *((u32 *)(rtcData.xCeMsg.ce_msg+4));
-                               u32 dataWord2 = *((u32 *)(rtcData.xCeMsg.ce_msg+8));
-                               u8 year = (dataWord1 >> 16) & 0x000000FF;
-                               u8 sec = (dataWord1 >> 8) & 0x000000FF;
-                               u8 min = dataWord1 & 0x000000FF;
-                               u8 hour = (dataWord2 >> 24) & 0x000000FF;
-                               u8 day = (dataWord2 >> 8) & 0x000000FF;
-                               u8 mon = dataWord2 & 0x000000FF;
-
-                               BCD_TO_BIN(sec);
-                               BCD_TO_BIN(min);
-                               BCD_TO_BIN(hour);
-                               BCD_TO_BIN(day);
-                               BCD_TO_BIN(mon);
-                               BCD_TO_BIN(year);
-
-                               if (year <= 69)
-                                       year += 100;
-           
-                               tm->tm_sec = sec;
-                               tm->tm_min = min;
-                               tm->tm_hour = hour;
-                               tm->tm_mday = day;
-                               tm->tm_mon = mon;
-                               tm->tm_year = year;
-                       }
-               } else {
-                       rc = rtcData.xRc;
-                       tm->tm_sec = 0;
-                       tm->tm_min = 0;
-                       tm->tm_hour = 0;
-                       tm->tm_mday = 15;
-                       tm->tm_mon = 5;
-                       tm->tm_year = 52;
 
-               }
-               tm->tm_wday = 0;
-               tm->tm_yday = 0;
-               tm->tm_isdst = 0;
-       }
+       ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
+       if (!ent)
+               return 1;
+       ent->nlink = 1;
+       ent->data = (void *)0;
+       ent->read_proc = proc_mf_dump_side;
+       ent->write_proc = proc_mf_change_side;
+
+       ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
+       if (!ent)
+               return 1;
+       ent->nlink = 1;
+       ent->data = (void *)0;
+       ent->read_proc = proc_mf_dump_src;
+       ent->write_proc = proc_mf_change_src;
 
-       return rc;
+       return 0;
 }
 
-int mf_setRtc(struct rtc_time * tm)
-{
-       char ceTime[12] = "\x00\x00\x00\x41\x00\x00\x00\x00\x00\x00\x00\x00";
-       u8 day, mon, hour, min, sec, y1, y2;
-       unsigned year;
-    
-       year = 1900 + tm->tm_year;
-       y1 = year / 100;
-       y2 = year % 100;
-    
-       sec = tm->tm_sec;
-       min = tm->tm_min;
-       hour = tm->tm_hour;
-       day = tm->tm_mday;
-       mon = tm->tm_mon + 1;
-           
-       BIN_TO_BCD(sec);
-       BIN_TO_BCD(min);
-       BIN_TO_BCD(hour);
-       BIN_TO_BCD(mon);
-       BIN_TO_BCD(day);
-       BIN_TO_BCD(y1);
-       BIN_TO_BCD(y2);
+__initcall(mf_proc_init);
 
-       ceTime[4] = y1;
-       ceTime[5] = y2;
-       ceTime[6] = sec;
-       ceTime[7] = min;
-       ceTime[8] = hour;
-       ceTime[10] = day;
-       ceTime[11] = mon;
-   
-       return signal_ce_msg(ceTime, NULL);
-}
+#endif /* CONFIG_PROC_FS */
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);
index 49ddf5e..f3644ad 100644 (file)
@@ -43,9 +43,9 @@ static struct nvram_partition * nvram_part;
 static long nvram_error_log_index = -1;
 static long nvram_error_log_size = 0;
 
-volatile int no_more_logging = 1; /* Until we initialize everything,
-                                  * make sure we don't try logging
-                                  * anything */
+int no_logging = 1;    /* Until we initialize everything,
+                        * make sure we don't try logging
+                        * anything */
 
 extern volatile int error_log_cnt;
 
@@ -77,7 +77,7 @@ static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
 }
 
 
-static ssize_t dev_nvram_read(struct file *file, char *buf,
+static ssize_t dev_nvram_read(struct file *file, char __user *buf,
                          size_t count, loff_t *ppos)
 {
        ssize_t len;
@@ -117,7 +117,7 @@ static ssize_t dev_nvram_read(struct file *file, char *buf,
 
 }
 
-static ssize_t dev_nvram_write(struct file *file, const char *buf,
+static ssize_t dev_nvram_write(struct file *file, const char __user *buf,
                           size_t count, loff_t *ppos)
 {
        ssize_t len;
@@ -640,7 +640,7 @@ int nvram_write_error_log(char * buff, int length, unsigned int err_type)
        loff_t tmp_index;
        struct err_log_info info;
        
-       if (no_more_logging) {
+       if (no_logging) {
                return -EPERM;
        }
 
@@ -711,7 +711,7 @@ int nvram_read_error_log(char * buff, int length, unsigned int * err_type)
 /* This doesn't actually zero anything, but it sets the event_logged
  * word to tell that this event is safely in syslog.
  */
-int nvram_clear_error_log()
+int nvram_clear_error_log(void)
 {
        loff_t tmp_index;
        int clear_word = ERR_FLAG_ALREADY_LOGGED;
index abbbe28..2946121 100644 (file)
@@ -276,7 +276,7 @@ static void iommu_buses_init(void)
                first_phb = 0;
 
                for (dn = first_dn; dn != NULL; dn = dn->sibling)
-                       iommu_devnode_init(dn);
+                       iommu_devnode_init_pSeries(dn);
        }
 }
 
@@ -290,7 +290,11 @@ static void iommu_buses_init_lpar(struct list_head *bus_list)
 
        for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
                bus = pci_bus_b(ln);
-               busdn = PCI_GET_DN(bus);
+
+               if (bus->self)
+                       busdn = pci_device_to_OF_node(bus->self);
+               else
+                       busdn = bus->sysdata;   /* must be a phb */
 
                dma_window = (unsigned int *)get_property(busdn, "ibm,dma-window", NULL);
                if (dma_window) {
@@ -298,7 +302,7 @@ static void iommu_buses_init_lpar(struct list_head *bus_list)
                         * Do it now because iommu_table_setparms_lpar needs it.
                         */
                        busdn->bussubno = bus->number;
-                       iommu_devnode_init(busdn);
+                       iommu_devnode_init_pSeries(busdn);
                }
 
                /* look for a window on a bridge even if the PHB had one */
@@ -317,19 +321,16 @@ static void iommu_table_setparms(struct pci_controller *phb,
 
        node = (struct device_node *)phb->arch_data;
 
-       if (get_property(node, "linux,has-tce-table", NULL) == NULL) {
-               printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has no tce table !\n",
-                     dn->full_name);
-               return;
-       }
        basep = (unsigned long *)get_property(node, "linux,tce-base", NULL);
        sizep = (unsigned int *)get_property(node, "linux,tce-size", NULL);
        if (basep == NULL || sizep == NULL) {
-               printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has missing tce"
-                      " entries !\n", dn->full_name);
+               printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has "
+                               "missing tce entries !\n", dn->full_name);
                return;
        }
-       memset((void *)(*basep), 0, *sizep);
+
+       tbl->it_base = (unsigned long)__va(*basep);
+       memset((void *)tbl->it_base, 0, *sizep);
 
        tbl->it_busno = phb->bus->number;
        
@@ -353,7 +354,6 @@ static void iommu_table_setparms(struct pci_controller *phb,
        if (phb->dma_window_base_cur > (1 << 19))
                panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); 
        
-       tbl->it_base = *basep;
        tbl->it_index = 0;
        tbl->it_entrysize = sizeof(union tce_entry);
        tbl->it_blocksize = 16;
@@ -397,7 +397,7 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
 }
 
 
-void iommu_devnode_init(struct device_node *dn)
+void iommu_devnode_init_pSeries(struct device_node *dn)
 {
        struct iommu_table *tbl;
 
@@ -412,7 +412,6 @@ void iommu_devnode_init(struct device_node *dn)
        dn->iommu_table = iommu_init_table(tbl);
 }
 
-
 void iommu_setup_pSeries(void)
 {
        struct pci_dev *dev = NULL;
@@ -427,8 +426,8 @@ void iommu_setup_pSeries(void)
         * pci device_node.  This means get_iommu_table() won't need to search
         * up the device tree to find it.
         */
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-               mydn = dn = PCI_GET_DN(dev);
+       for_each_pci_dev(dev) {
+               mydn = dn = pci_device_to_OF_node(dev);
 
                while (dn && dn->iommu_table == NULL)
                        dn = dn->parent;
@@ -437,7 +436,6 @@ void iommu_setup_pSeries(void)
        }
 }
 
-
 /* These are called very early. */
 void tce_init_pSeries(void)
 {
index 80e0289..3787957 100644 (file)
 #include <asm/nvram.h>
 
 #include "i8259.h"
-#include "open_pic.h"
 #include <asm/xics.h>
 #include <asm/ppcdebug.h>
 #include <asm/cputable.h>
 
+#include "mpic.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);
 
@@ -82,6 +81,8 @@ 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 */
+extern void generic_find_legacy_serial_ports(unsigned int *default_speed);
+
 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.
@@ -91,6 +92,9 @@ extern unsigned long loops_per_jiffy;
 extern unsigned long ppc_proc_freq;
 extern unsigned long ppc_tb_freq;
 
+static volatile void __iomem * chrp_int_ack_special;
+struct mpic *pSeries_mpic;
+
 void pSeries_get_cpuinfo(struct seq_file *m)
 {
        struct device_node *root;
@@ -120,15 +124,84 @@ static void __init fwnmi_init(void)
                fwnmi_active = 1;
 }
 
-static void __init pSeries_setup_arch(void)
+static int pSeries_irq_cascade(struct pt_regs *regs, void *data)
+{
+       if (chrp_int_ack_special)
+               return readb(chrp_int_ack_special);
+       else
+               return i8259_irq(smp_processor_id());
+}
+
+static void __init pSeries_init_mpic(void)
+{
+        unsigned int *addrp;
+       struct device_node *np;
+        int i;
+
+       /* All ISUs are setup, complete initialization */
+       mpic_init(pSeries_mpic);
+
+       /* Check what kind of cascade ACK we have */
+        if (!(np = of_find_node_by_name(NULL, "pci"))
+            || !(addrp = (unsigned int *)
+                 get_property(np, "8259-interrupt-acknowledge", NULL)))
+                printk(KERN_ERR "Cannot find pci to get ack address\n");
+        else
+               chrp_int_ack_special = ioremap(addrp[prom_n_addr_cells(np)-1], 1);
+       of_node_put(np);
+
+       /* Setup the legacy interrupts & controller */
+        for (i = 0; i < NUM_ISA_INTERRUPTS; i++)
+                irq_desc[i].handler = &i8259_pic;
+       i8259_init(0);
+
+       /* Hook cascade to mpic */
+       mpic_setup_cascade(NUM_ISA_INTERRUPTS, pSeries_irq_cascade, NULL);
+}
+
+static void __init pSeries_setup_mpic(void)
 {
-       struct device_node *root;
        unsigned int *opprop;
+       unsigned long openpic_addr = 0;
+        unsigned char senses[NR_IRQS - NUM_ISA_INTERRUPTS];
+        struct device_node *root;
+       int irq_count;
 
+       /* 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);
+
+               for (openpic_addr = 0; n > 0; --n)
+                       openpic_addr = (openpic_addr << 32) + *opprop++;
+               printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
+       }
+       of_node_put(root);
+
+       BUG_ON(openpic_addr == 0);
+
+       /* Get the sense values from OF */
+       prom_get_irq_senses(senses, NUM_ISA_INTERRUPTS, NR_IRQS);
+       
+       /* Setup the openpic driver */
+       irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */
+       pSeries_mpic = mpic_alloc(openpic_addr, MPIC_PRIMARY,
+                                 16, 16, irq_count, /* isu size, irq offset, irq count */ 
+                                 NR_IRQS - 4, /* ipi offset */
+                                 senses, irq_count, /* sense & sense size */
+                                 " MPIC     ");
+}
+
+static void __init pSeries_setup_arch(void)
+{
        /* 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;
+               ppc_md.init_IRQ       = pSeries_init_mpic; 
+               ppc_md.get_irq        = mpic_get_irq;
+               /* Allocate the mpic now, so that find_and_init_phbs() can
+                * fill the ISUs */
+               pSeries_setup_mpic();
        } else {
                ppc_md.init_IRQ       = xics_init_IRQ;
                ppc_md.get_irq        = xics_get_irq;
@@ -156,26 +229,14 @@ static void __init pSeries_setup_arch(void)
        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();
+
+       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
+               vpa_init(boot_cpuid);
 }
 
 static int __init pSeries_init_panel(void)
@@ -189,75 +250,6 @@ static int __init pSeries_init_panel(void)
 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().
@@ -330,6 +322,20 @@ static  void __init pSeries_discover_pic(void)
        }
 }
 
+static void pSeries_cpu_die(void)
+{
+       local_irq_disable();
+       /* Some hardware requires clearing the CPPR, while other hardware does not
+        * it is safe either way
+        */
+       pSeriesLP_cppr_info(0, 0);
+       rtas_stop_self();
+       /* Should never get here... */
+       BUG();
+       for(;;);
+}
+
+
 /*
  * Early initialization.  Relocation is on but do not reference unbolted pages
  */
@@ -337,6 +343,7 @@ static void __init pSeries_init_early(void)
 {
        void *comport;
        int iommu_off = 0;
+       unsigned int default_speed;
 
        DBG(" -> pSeries_init_early()\n");
 
@@ -350,14 +357,14 @@ static void __init pSeries_init_early(void)
                             get_property(of_chosen, "linux,iommu-off", NULL));
        }
 
-       pSeries_find_serial_port();
+       generic_find_legacy_serial_ports(&default_speed);
 
        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);
+               udbg_init_uart(comport, default_speed);
 
                ppc_md.udbg_putc = udbg_putc;
                ppc_md.udbg_getc = udbg_getc;
@@ -542,6 +549,31 @@ static void __init pSeries_calibrate_decr(void)
        setup_default_decr();
 }
 
+static int pSeries_check_legacy_ioport(unsigned int baseport)
+{
+       struct device_node *np;
+
+#define I8042_DATA_REG 0x60
+#define FDC_BASE       0x3f0
+
+
+       switch(baseport) {
+       case I8042_DATA_REG:
+               np = of_find_node_by_type(NULL, "8042");
+               if (np == NULL)
+                       return -ENODEV;
+               of_node_put(np);
+               break;
+       case FDC_BASE:
+               np = of_find_node_by_type(NULL, "fdc");
+               if (np == NULL)
+                       return -ENODEV;
+               of_node_put(np);
+               break;
+       }
+       return 0;
+}
+
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
@@ -571,9 +603,11 @@ struct machdep_calls __initdata pSeries_md = {
        .power_off              = rtas_power_off,
        .halt                   = rtas_halt,
        .panic                  = rtas_os_term,
+       .cpu_die                = pSeries_cpu_die,
        .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,
+       .check_legacy_ioport    = pSeries_check_legacy_ioport,
 };
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");
+}
+
index 951831f..dd5ad02 100644 (file)
 #include <asm/iSeries/iSeries_pci.h>
 #endif /* CONFIG_PPC_ISERIES */
 
+/*
+ * We can use ->sysdata directly and avoid the extra work in
+ * pci_device_to_OF_node since ->sysdata will have been initialised
+ * in the iommu init code for all devices.
+ */
+#define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata))
+
 static inline struct iommu_table *devnode_table(struct pci_dev *dev)
 {
        if (!dev)
index 4d69b3a..40e1c50 100644 (file)
@@ -18,7 +18,6 @@ extern void pmac_calibrate_decr(void);
 extern void pmac_pcibios_fixup(void);
 extern void pmac_pci_init(void);
 extern void pmac_setup_pci_dma(void);
-extern void fixup_k2_sata(struct pci_dev* dev);
 extern void pmac_check_ht_link(void);
 
 extern void pmac_setup_smp(void);
index 52da757..f3f39e8 100644 (file)
  *  properties parser
  */
 
+#undef DEBUG
+
 #include <linux/config.h>
 #include <linux/types.h>
-#include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/module.h>
 
 #define MAX_LOW_I2C_HOST       4
 
-#if 1
+#ifdef DEBUG
 #define DBG(x...) do {\
                printk(KERN_DEBUG "KW:" x);     \
        } while(0)
 #else
-#define DBGG(x...)
+#define DBG(x...)
 #endif
 
 struct low_i2c_host;
@@ -50,11 +51,11 @@ struct low_i2c_host
        struct device_node      *np;            /* OF device node */
        struct semaphore        mutex;          /* Access mutex for use by i2c-keywest */
        low_i2c_func_t          func;           /* Access function */
-       unsigned                is_open : 1;    /* Poor man's access control */
+       unsigned int            is_open : 1;    /* Poor man's access control */
        int                     mode;           /* Current mode */
        int                     channel;        /* Current channel */
        int                     num_channels;   /* Number of channels */
-       unsigned long           base;           /* For keywest-i2c, base address */
+       void __iomem            *base;          /* For keywest-i2c, base address */
        int                     bsteps;         /* And register stepping */
        int                     speed;          /* And speed */
 };
@@ -154,14 +155,12 @@ static const char *__kw_state_names[] = {
 
 static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
 {
-       return in_8(((volatile u8 *)host->base)
-               + (((unsigned)reg) << host->bsteps));
+       return readb(host->base + (((unsigned int)reg) << host->bsteps));
 }
 
 static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
 {
-       out_8(((volatile u8 *)host->base)
-               + (((unsigned)reg) << host->bsteps), val);
+       writeb(val, host->base + (((unsigned)reg) << host->bsteps));
        (void)__kw_read_reg(host, reg_subaddr);
 }
 
@@ -174,14 +173,19 @@ static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
  */
 static u8 kw_wait_interrupt(struct low_i2c_host* host)
 {
-       int i;
+       int i, j;
        u8 isr;
        
-       for (i = 0; i < 200000; i++) {
+       for (i = 0; i < 100000; i++) {
                isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
                if (isr != 0)
                        return isr;
-               udelay(1);
+
+               /* This code is used with the timebase frozen, we cannot rely
+                * on udelay ! For now, just use a bogus loop
+                */
+               for (j = 1; j < 10000; j++)
+                       mb();
        }
        return isr;
 }
@@ -190,6 +194,8 @@ static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int
 {
        u8 ack;
 
+       DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr);
+
        if (isr == 0) {
                if (state != state_stop) {
                        DBG("KW: Timeout !\n");
@@ -301,11 +307,9 @@ static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr,
                break;
        case pmac_low_i2c_mode_stdsub:
                mode_reg |= KW_I2C_MODE_STANDARDSUB;
-               kw_write_reg(reg_subaddr, subaddr);
                break;
        case pmac_low_i2c_mode_combined:
                mode_reg |= KW_I2C_MODE_COMBINED;
-               kw_write_reg(reg_subaddr, subaddr);
                break;
        }
 
@@ -317,6 +321,11 @@ static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr,
        /* Set up address and r/w bit */
        kw_write_reg(reg_addr, addr);
 
+       /* Set up the sub address */
+       if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
+           || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
+               kw_write_reg(reg_subaddr, subaddr);
+
        /* Start sending address & disable interrupt*/
        kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
        kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
@@ -333,7 +342,7 @@ static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr,
 static void keywest_low_i2c_add(struct device_node *np)
 {
        struct low_i2c_host     *host = find_low_i2c_host(NULL);
-       unsigned long           *psteps, *prate, steps, aoffset = 0;
+       u32                     *psteps, *prate, steps, aoffset = 0;
        struct device_node      *parent;
 
        if (host == NULL) {
@@ -345,7 +354,7 @@ static void keywest_low_i2c_add(struct device_node *np)
 
        init_MUTEX(&host->mutex);
        host->np = of_node_get(np);     
-       psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL);
+       psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
        steps = psteps ? (*psteps) : 0x10;
        for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
                steps >>= 1;
@@ -357,7 +366,7 @@ static void keywest_low_i2c_add(struct device_node *np)
        }
        /* Select interface rate */
        host->speed = KW_I2C_MODE_100KHZ;
-       prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL);
+       prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
        if (prate) switch(*prate) {
        case 100:
                host->speed = KW_I2C_MODE_100KHZ;
@@ -369,8 +378,9 @@ static void keywest_low_i2c_add(struct device_node *np)
                host->speed = KW_I2C_MODE_25KHZ;
                break;
        }       
+
        host->mode = pmac_low_i2c_mode_std;
-       host->base = (unsigned long)ioremap(np->addrs[0].address + aoffset,
+       host->base = ioremap(np->addrs[0].address + aoffset,
                                                np->addrs[0].size);
        host->func = keywest_low_i2c_func;
 }
index 9e1a069..00d1db4 100644 (file)
 #define DBG(x...)
 #endif
 
-extern int pci_probe_only;
-extern int pci_read_irq_line(struct pci_dev *pci_dev);
-
 /* XXX Could be per-controller, but I don't think we risk anything by
  * assuming we won't have both UniNorth and Bandit */
 static int has_uninorth;
 static struct pci_controller *u3_agp;
-u8 pci_cache_line_size;
 struct pci_dev *k2_skiplist[2];
 
 static int __init fixup_one_level_bus_range(struct device_node *node, int higher)
@@ -150,16 +146,9 @@ static int __pmac macrisc_read_config(struct pci_bus *bus, unsigned int devfn,
                                      int offset, int len, u32 *val)
 {
        struct pci_controller *hose;
-       struct device_node *busdn;
        unsigned long addr;
 
-       if (bus->self)
-               busdn = pci_device_to_OF_node(bus->self);
-       else
-               busdn = bus->sysdata;   /* must be a phb */
-       if (busdn == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       hose = busdn->phb;
+       hose = pci_bus_to_host(bus);
        if (hose == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -188,16 +177,9 @@ static int __pmac macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
                                       int offset, int len, u32 val)
 {
        struct pci_controller *hose;
-       struct device_node *busdn;
        unsigned long addr;
 
-       if (bus->self)
-               busdn = pci_device_to_OF_node(bus->self);
-       else
-               busdn = bus->sysdata;   /* must be a phb */
-       if (busdn == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       hose = busdn->phb;
+       hose = pci_bus_to_host(bus);
        if (hose == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -236,14 +218,44 @@ static struct pci_ops macrisc_pci_ops =
  * implement self-view of the HT host yet
  */
 
-static int skip_k2_device(struct pci_bus *bus, unsigned int devfn)
+/*
+ * This function deals with some "special cases" devices.
+ *
+ *  0 -> No special case
+ *  1 -> Skip the device but act as if the access was successfull
+ *       (return 0xff's on reads, eventually, cache config space
+ *       accesses in a later version)
+ * -1 -> Hide the device (unsuccessful acess)
+ */
+static int u3_ht_skip_device(struct pci_controller *hose,
+                            struct pci_bus *bus, unsigned int devfn)
 {
+       struct device_node *busdn, *dn;
        int i;
 
+       /*
+        * When a device in K2 is powered down, we die on config
+        * cycle accesses. Fix that here.
+        */
        for (i=0; i<2; i++)
                if (k2_skiplist[i] && k2_skiplist[i]->bus == bus &&
                    k2_skiplist[i]->devfn == devfn)
                        return 1;
+
+       /* We only allow config cycles to devices that are in OF device-tree
+        * as we are apparently having some weird things going on with some
+        * revs of K2 on recent G5s
+        */
+       if (bus->self)
+               busdn = pci_device_to_OF_node(bus->self);
+       else
+               busdn = hose->arch_data;
+       for (dn = busdn->child; dn; dn = dn->sibling)
+               if (dn->devfn == devfn)
+                       break;
+       if (dn == NULL)
+               return -1;
+
        return 0;
 }
 
@@ -259,8 +271,7 @@ static unsigned long __pmac u3_ht_cfg_access(struct pci_controller* hose,
 {
        if (bus == hose->first_busno) {
                /* For now, we don't self probe U3 HT bridge */
-               if (PCI_FUNC(devfn) != 0 || PCI_SLOT(devfn) > 7 ||
-                   PCI_SLOT(devfn) < 1)
+               if (PCI_SLOT(devfn) == 0)
                        return 0;
                return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset);
        } else
@@ -271,39 +282,21 @@ static int __pmac u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
                                    int offset, int len, u32 *val)
 {
        struct pci_controller *hose;
-       struct device_node *busdn, *dn;
        unsigned long addr;
 
-       if (bus->self)
-               busdn = pci_device_to_OF_node(bus->self);
-       else
-               busdn = bus->sysdata;   /* must be a phb */
-       if (busdn == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       hose = busdn->phb;
-       if (hose == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
 
-       /* We only allow config cycles to devices that are in OF device-tree
-        * as we are apparently having some weird things going on with some
-        * revs of K2 on recent G5s
-        */
-       for (dn = busdn->child; dn; dn = dn->sibling)
-               if (dn->devfn == devfn)
-                       break;
-       if (dn == NULL)
+       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;
-       /*
-        * When a device in K2 is powered down, we die on config
-        * cycle accesses. Fix that here. We may ultimately want
-        * to cache the config space for those instead of returning
-        * 0xffffffff's to make life easier to HW detection tools
-        */
-       if (skip_k2_device(bus, devfn)) {
+
+       switch (u3_ht_skip_device(hose, bus, devfn)) {
+       case 0:
+               break;
+       case 1:
                switch (len) {
                case 1:
                        *val = 0xff; break;
@@ -313,6 +306,8 @@ static int __pmac u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
                        *val = 0xfffffffful; break;
                }
                return PCIBIOS_SUCCESSFUL;
+       default:
+               return PCIBIOS_DEVICE_NOT_FOUND;
        }
 
        /*
@@ -337,28 +332,24 @@ static int __pmac u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
                                     int offset, int len, u32 val)
 {
        struct pci_controller *hose;
-       struct device_node *busdn;
        unsigned long addr;
 
-       if (bus->self)
-               busdn = pci_device_to_OF_node(bus->self);
-       else
-               busdn = bus->sysdata;   /* must be a phb */
-       if (busdn == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       hose = busdn->phb;
+       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;
-       /*
-        * When a device in K2 is powered down, we die on config
-        * cycle accesses. Fix that here.
-        */
-       if (skip_k2_device(bus, devfn))
+
+       switch (u3_ht_skip_device(hose, bus, devfn)) {
+       case 0:
+               break;
+       case 1:
                return PCIBIOS_SUCCESSFUL;
+       default:
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
 
        /*
         * Note: the caller has already checked that offset is
@@ -513,7 +504,7 @@ static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose,
        dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
        if (!dt_ranges)
                return;
-       /*      lc_ranges = (unsigned int *) alloc_bootmem(rlen);*/
+       /*      lc_ranges = alloc_bootmem(rlen);*/
        lc_ranges = static_lc_ranges;
        if (!lc_ranges)
                return; /* what can we do here ? */
@@ -623,15 +614,17 @@ static int __init add_bridge(struct device_node *dev)
                                       dev->full_name);
                }
 
-               hose = pci_alloc_pci_controller(phb_type_apple);
-               if (!hose)
-                       return -ENOMEM;
+       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 = (struct property *)alloc_bootmem(sizeof(struct property) +
-                       sizeof(hose->global_number));        
+       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";
@@ -669,13 +662,12 @@ void __init pmac_pcibios_fixup(void)
 {
        struct pci_dev *dev = NULL;
 
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+       for_each_pci_dev(dev)
                pci_read_irq_line(dev);
 
        pci_fix_bus_sysdata();
 
        iommu_setup_u3();
-
 }
 
 static void __init pmac_fixup_phb_resources(void)
@@ -747,14 +739,9 @@ void __init pmac_pci_init(void)
 
        pmac_check_ht_link();
 
-       /* Tell pci.c to use the common resource allocation mecanism */
-       pci_probe_only = 0;
+       /* Tell pci.c to not use the common resource allocation mecanism */
+       pci_probe_only = 1;
        
-       /* HT don't do more than 64 bytes transfers. FIXME: Deal with
-        * the exception of U3/AGP (hook into pci_set_mwi)
-        */
-       pci_cache_line_size = 16; /* 64 bytes */
-
        /* Allow all IO */
        io_page_mask = -1;
 }
@@ -763,7 +750,7 @@ void __init pmac_pci_init(void)
  * Disable second function on K2-SATA, it's broken
  * and disable IO BARs on first one
  */
-void fixup_k2_sata(struct pci_dev* dev)
+static void fixup_k2_sata(struct pci_dev* dev)
 {
        int i;
        u16 cmd;
index 3d1de0f..92b0e3c 100644 (file)
 #include <linux/irq.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
+#include <linux/bitops.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>
@@ -73,6 +72,7 @@
 #include <asm/lmb.h>
 
 #include "pmac.h"
+#include "mpic.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -320,29 +320,9 @@ void __init pmac_init_early(void)
        DBG(" <- pmac_init_early\n");
 }
 
-extern void* OpenPIC_Addr;
-extern void* OpenPIC2_Addr;
-extern u_int OpenPIC_NumInitSenses;
-extern u_char *OpenPIC_InitSenses;
-extern void openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
-                        int programmer_switch_irq);
-extern void openpic2_init(int offset);
-extern int openpic_get_irq(struct pt_regs *regs);
-extern int openpic2_get_irq(struct pt_regs *regs);
-
-static int pmac_cascade_irq = -1;
-
-static irqreturn_t pmac_u3_do_cascade(int cpl, void *dev_id, struct pt_regs *regs)
+static int pmac_u3_cascade(struct pt_regs *regs, void *data)
 {
-       int irq;
-
-       for (;;) {
-               irq = openpic2_get_irq(regs);
-               if (irq == -1)
-                       break;
-               ppc_irq_dispatch_handler(regs, irq);
-       }
-       return IRQ_HANDLED;
+       return mpic_get_one_irq((struct mpic *)data, regs);
 }
 
 static __init void pmac_init_IRQ(void)
@@ -350,6 +330,7 @@ static __init void pmac_init_IRQ(void)
         struct device_node *irqctrler  = NULL;
         struct device_node *irqctrler2 = NULL;
        struct device_node *np = NULL;
+       struct mpic *mpic1, *mpic2;
 
        /* We first try to detect Apple's new Core99 chipset, since mac-io
         * is quite different on those machines and contains an IBM MPIC2.
@@ -369,44 +350,37 @@ static __init void pmac_init_IRQ(void)
                       (unsigned int)irqctrler->addrs[0].address);
 
                prom_get_irq_senses(senses, 0, 128);
-               OpenPIC_InitSenses = senses;
-               OpenPIC_NumInitSenses = 128;
-               OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
-                                      irqctrler->addrs[0].size);
-               openpic_init(1, 0, NULL, -1);
+               mpic1 = mpic_alloc(irqctrler->addrs[0].address,
+                                  MPIC_PRIMARY | MPIC_WANTS_RESET,
+                                  0, 0, 128, 256, senses, 128, " K2-MPIC  ");
+               BUG_ON(mpic1 == NULL);
+               mpic_init(mpic1);               
 
                if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
                    irqctrler2->n_addrs > 0) {
                        printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
                               (u32)irqctrler2->addrs[0].address,
                               irqctrler2->intrs[0].line);
+
                        pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
-                       OpenPIC2_Addr = ioremap(irqctrler2->addrs[0].address,
-                                               irqctrler2->addrs[0].size);
                        prom_get_irq_senses(senses, 128, 128 + 128);
-                       OpenPIC_InitSenses = senses;
-                       OpenPIC_NumInitSenses = 128;
-                       openpic2_init(128);
-                       pmac_cascade_irq = irqctrler2->intrs[0].line;
+
+                       /* We don't need to set MPIC_BROKEN_U3 here since we don't have
+                        * hypertransport interrupts routed to it
+                        */
+                       mpic2 = mpic_alloc(irqctrler2->addrs[0].address,
+                                          MPIC_BIG_ENDIAN | MPIC_WANTS_RESET,
+                                          0, 128, 128, 0, senses, 128, " U3-MPIC  ");
+                       BUG_ON(mpic2 == NULL);
+                       mpic_init(mpic2);
+                       mpic_setup_cascade(irqctrler2->intrs[0].line,
+                                          pmac_u3_cascade, mpic2);
                }
        }
        of_node_put(irqctrler);
        of_node_put(irqctrler2);
 }
 
-/* We cannot do request_irq too early ... Right now, we get the
- * cascade as a core_initcall, which should be fine for our needs
- */
-static int __init pmac_irq_cascade_init(void)
-{
-       if (request_irq(pmac_cascade_irq, pmac_u3_do_cascade, 0,
-                       "U3->K2 Cascade", NULL))
-               printk(KERN_ERR "Unable to get OpenPIC IRQ for cascade\n");
-       return 0;
-}
-
-core_initcall(pmac_irq_cascade_init);
-
 static void __init pmac_progress(char *s, unsigned short hex)
 {
        if (sccdbg) {
@@ -421,6 +395,15 @@ static void __init pmac_progress(char *s, unsigned short hex)
 #endif /* CONFIG_BOOTX_TEXT */
 }
 
+/*
+ * pmac has no legacy IO, anything calling this function has to
+ * fail or bad things will happen
+ */
+static int pmac_check_legacy_ioport(unsigned int baseport)
+{
+       return -ENODEV;
+}
+
 static int __init pmac_declare_of_platform_devices(void)
 {
        struct device_node *np;
@@ -464,7 +447,7 @@ struct machdep_calls __initdata pmac_md = {
        .init_early             = pmac_init_early,
                .get_cpuinfo            = pmac_show_cpuinfo,
        .init_IRQ               = pmac_init_IRQ,
-       .get_irq                = openpic_get_irq,
+       .get_irq                = mpic_get_irq,
        .pcibios_fixup          = pmac_pcibios_fixup,
        .restart                = pmac_restart,
        .power_off              = pmac_power_off,
@@ -475,4 +458,5 @@ struct machdep_calls __initdata pmac_md = {
        .calibrate_decr         = pmac_calibrate_decr,
        .feature_call           = pmac_do_feature_call,
        .progress               = pmac_progress,
+       .check_legacy_ioport    = pmac_check_legacy_ioport
 };
index ed172cd..07bf321 100644 (file)
@@ -33,7 +33,8 @@
 #include <asm/prom.h>
 
 static loff_t  page_map_seek( struct file *file, loff_t off, int whence);
-static ssize_t page_map_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos);
+static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes,
+                             loff_t *ppos);
 static int     page_map_mmap( struct file *file, struct vm_area_struct *vma );
 
 static struct file_operations page_map_fops = {
@@ -161,7 +162,8 @@ static loff_t page_map_seek( struct file *file, loff_t off, int whence)
        return (file->f_pos = new);
 }
 
-static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes,
+                             loff_t *ppos)
 {
        struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
        return simple_read_from_buffer(buf, nbytes, ppos, dp->data, dp->size);
@@ -176,7 +178,8 @@ static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
        if ((vma->vm_end - vma->vm_start) > dp->size)
                return -EINVAL;
 
-       remap_page_range( vma, vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot );
+       remap_pfn_range(vma, vma->vm_start, __pa(dp->data) >> PAGE_SHIFT,
+                                               dp->size, vma->vm_page_prot);
        return 0;
 }
 
@@ -207,7 +210,8 @@ static void proc_ppc64_create_ofdt(void)
  * whole nodes along with their properties.  Operations on individual
  * properties are not implemented (yet).
  */
-static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
+static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count,
+                         loff_t *off)
 {
        int rv = 0;
        char *kbuf;
@@ -301,7 +305,8 @@ out:
        return rv;
 }
 
-static struct property *new_property(const char *name, const int length, const unsigned char *value, struct property *last)
+static struct property *new_property(const char *name, const int length,
+                                    const unsigned char *value, struct property *last)
 {
        struct property *new = kmalloc(sizeof(*new), GFP_KERNEL);
 
@@ -342,7 +347,8 @@ cleanup:
  * this function does no allocation or copying of the data.  Return value
  * is set to the next name in buf, or NULL on error.
  */
-static char * parse_next_property(char *buf, char *end, char **name, int *length, unsigned char **value)
+static char * parse_next_property(char *buf, char *end, char **name, int *length,
+                                 unsigned char **value)
 {
        char *tmp;
 
@@ -350,13 +356,15 @@ static char * parse_next_property(char *buf, char *end, char **name, int *length
 
        tmp = strchr(buf, ' ');
        if (!tmp) {
-               printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
+               printk(KERN_ERR "property parse failed in %s at line %d\n",
+                      __FUNCTION__, __LINE__);
                return NULL;
        }
        *tmp = '\0';
 
        if (++tmp >= end) {
-               printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
+               printk(KERN_ERR "property parse failed in %s at line %d\n",
+                      __FUNCTION__, __LINE__);
                return NULL;
        }
 
@@ -364,11 +372,13 @@ static char * parse_next_property(char *buf, char *end, char **name, int *length
        *length = -1;
        *length = simple_strtoul(tmp, &tmp, 10);
        if (*length == -1) {
-               printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
+               printk(KERN_ERR "property parse failed in %s at line %d\n", 
+                      __FUNCTION__, __LINE__);
                return NULL;
        }
        if (*tmp != ' ' || ++tmp >= end) {
-               printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
+               printk(KERN_ERR "property parse failed in %s at line %d\n",
+                      __FUNCTION__, __LINE__);
                return NULL;
        }
 
@@ -376,11 +386,13 @@ static char * parse_next_property(char *buf, char *end, char **name, int *length
        *value = tmp;
        tmp += *length;
        if (tmp > end) {
-               printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
+               printk(KERN_ERR "property parse failed in %s at line %d\n",
+                      __FUNCTION__, __LINE__);
                return NULL;
        }
        else if (tmp < end && *tmp != ' ' && *tmp != '\0') {
-               printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
+               printk(KERN_ERR "property parse failed in %s at line %d\n",
+                      __FUNCTION__, __LINE__);
                return NULL;
        }
        tmp++;
index f62bda7..e570799 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/stringify.h>
 #include <linux/delay.h>
 #include <linux/initrd.h>
+#include <linux/bitops.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/abs_addr.h>
@@ -42,7 +43,6 @@
 #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>
@@ -51,7 +51,6 @@
 #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>
@@ -160,8 +159,6 @@ extern void copy_and_flush(unsigned long dest, unsigned long src,
 
 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;
 
@@ -675,7 +672,7 @@ static void __init prom_init_mem(void)
        if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR )
                RELOC(alloc_top) = RELOC(rmo_top);
        else
-               RELOC(alloc_top) = min(0x40000000ul, RELOC(ram_top));
+               RELOC(alloc_top) = RELOC(rmo_top) = min(0x40000000ul, RELOC(ram_top));
        RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(klimit) - offset + 0x4000);
        RELOC(alloc_top_high) = RELOC(ram_top);
 
@@ -704,48 +701,51 @@ 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;
+       phandle prom_rtas, rtas_node;
+       u32 base, entry = 0;
+       u32 size = 0;
 
        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("...");
+       prom_debug("prom_rtas: %x\n", prom_rtas);
+       if (prom_rtas == (phandle) -1)
+               return;
 
-                       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");
+       prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size));
+       if (size == 0)
+               return;
 
-                       reserve_mem(base, size);
-               }
+       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_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));
+       rtas_node = call_prom("open", 1, 1, ADDR("/rtas"));
+       prom_printf("...");
 
-               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);
+       if (call_prom("call-method", 3, 2,
+                     ADDR("instantiate-rtas"),
+                     rtas_node, 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_rtas, "linux,rtas-base", &base, sizeof(base));
+       prom_setprop(prom_rtas, "linux,rtas-entry", &entry, sizeof(entry));
+
+       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");
 }
 
@@ -760,7 +760,7 @@ static void __init prom_initialize_tce_table(void)
        unsigned long offset = reloc_offset();
        char compatible[64], type[64], model[64];
        char *path = RELOC(prom_scratch);
-       u64 base, vbase, align;
+       u64 base, align;
        u32 minalign, minsize;
        u64 tce_entry, *tce_entryp;
        u64 local_alloc_top, local_alloc_bottom;
@@ -832,12 +832,9 @@ static void __init prom_initialize_tce_table(void)
                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-base", &base, sizeof(base));
                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));
@@ -952,9 +949,9 @@ static void __init prom_hold_cpus(void)
                        continue;
 
                /* Skip non-configured cpus. */
-               prom_getprop(node, "status", type, sizeof(type));
-               if (strcmp(type, RELOC("okay")) != 0)
-                       continue;
+               if (prom_getprop(node, "status", type, sizeof(type)) > 0)
+                       if (strcmp(type, RELOC("okay")) != 0)
+                               continue;
 
                reg = -1;
                prom_getprop(node, "reg", &reg, sizeof(reg));
@@ -991,12 +988,13 @@ static void __init prom_hold_cpus(void)
                        /* 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);
+                                 secondary_hold, reg);
 
                        for ( i = 0 ; (i < 100000000) && 
-                             (*acknowledge == ((unsigned long)-1)); i++ ) ;
+                             (*acknowledge == ((unsigned long)-1)); i++ )
+                               mb();
 
-                       if (*acknowledge == cpuid) {
+                       if (*acknowledge == reg) {
                                prom_printf("done\n");
                                /* We have to get every CPU out of OF,
                                 * even if we never start it. */
@@ -1110,6 +1108,16 @@ static void __init prom_init_stdout(void)
        }
 }
 
+static void __init prom_close_stdin(void)
+{
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+       ihandle val;
+
+       if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0)
+               call_prom("close", 1, 0, val);
+}
+
 static int __init prom_find_machine_type(void)
 {
        unsigned long offset = reloc_offset();
@@ -1130,6 +1138,8 @@ static int __init prom_find_machine_type(void)
                        if (strstr(p, RELOC("Power Macintosh")) ||
                            strstr(p, RELOC("MacRISC4")))
                                return PLATFORM_POWERMAC;
+                       if (strstr(p, RELOC("Momentum,Maple")))
+                               return PLATFORM_MAPLE;
                        i += sl + 1;
                }
        }
@@ -1161,7 +1171,7 @@ static int __init prom_set_color(ihandle ih, int i, int r, int g, int b)
  * 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)
+static void __init prom_check_displays(void)
 {
        unsigned long offset = reloc_offset();
        struct prom_t *_prom = PTRRELOC(&prom);
@@ -1602,11 +1612,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long
        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
         */
@@ -1691,6 +1696,9 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long
                prom_printf("copying OF device tree ...\n");
                flatten_device_tree();
 
+       /* in case stdin is USB and still active on IBM machines... */
+       prom_close_stdin();
+
        /*
         * Call OF "quiesce" method to shut down pending DMA's from
         * devices etc...
index 2bb0b39..051cac6 100644 (file)
@@ -267,6 +267,7 @@ static int dart_init(struct device_node *dart_node)
 
 void iommu_setup_u3(void)
 {
+       struct pci_controller *phb, *tmp;
        struct pci_dev *dev = NULL;
        struct device_node *dn;
 
@@ -290,7 +291,7 @@ void iommu_setup_u3(void)
        /* 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) {
+       for_each_pci_dev(dev) {
                /* 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
@@ -299,6 +300,11 @@ void iommu_setup_u3(void)
                if (dn)
                        dn->iommu_table = &iommu_table_u3;
        }
+       /* We also make sure we set all PHBs ... */
+       list_for_each_entry_safe(phb, tmp, &hose_list, list_node) {
+               dn = (struct device_node *)phb->arch_data;
+               dn->iommu_table = &iommu_table_u3;
+       }
 }
 
 void __init alloc_u3_dart_table(void)
index 1430ef5..cb20762 100644 (file)
@@ -263,7 +263,7 @@ emulate_altivec(struct pt_regs *regs)
        unsigned int va, vb, vc, vd;
        vector128 *vrs;
 
-       if (get_user(instr, (unsigned int *) regs->nip))
+       if (get_user(instr, (unsigned int __user *) regs->nip))
                return -EFAULT;
        if ((instr >> 26) != 4)
                return -EINVAL;         /* not an altivec instruction */
index 84ffb54..6e8d859 100644 (file)
@@ -28,7 +28,7 @@
  */
 
 #ifndef ATOMIC_DEC_AND_LOCK
-int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
        int counter;
        int newcount;
@@ -51,5 +51,5 @@ int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
        return 0;
 }
 
-EXPORT_SYMBOL(atomic_dec_and_lock);
+EXPORT_SYMBOL(_atomic_dec_and_lock);
 #endif /* ATOMIC_DEC_AND_LOCK */
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;
+}
index 0d8c8ab..77297fc 100644 (file)
@@ -387,33 +387,37 @@ static void native_flush_hash_range(unsigned long context,
        local_irq_restore(flags);
 }
 
-void hpte_init_native(void)
-{
 #ifdef CONFIG_PPC_PSERIES
-       struct device_node *root;
-       const char *model;
-#endif /* CONFIG_PPC_PSERIES */
+/* Disable TLB batching on nighthawk */
+static inline int tlb_batching_enabled(void)
+{
+       struct device_node *root = of_find_node_by_path("/");
+       int enabled = 1;
+
+       if (root) {
+               const char *model = get_property(root, "model", NULL);
+               if (model && !strcmp(model, "IBM,9076-N81"))
+                       enabled = 0;
+               of_node_put(root);
+       }
+
+       return enabled;
+}
+#else
+static inline int tlb_batching_enabled(void)
+{
+       return 1;
+}
+#endif
 
+void hpte_init_native(void)
+{
        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:
+       if (tlb_batching_enabled())
+               ppc_md.flush_hash_range = native_flush_hash_range;
        htab_finish_init();
 }
index f90dd1f..fe65f52 100644 (file)
@@ -37,7 +37,7 @@
 
 static inline unsigned long mmap_base(void)
 {
-       unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur;
+       unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
 
        if (gap < MIN_GAP)
                gap = MIN_GAP;
@@ -58,7 +58,7 @@ static inline int mmap_is_legacy(void)
        if (current->personality & ADDR_COMPAT_LAYOUT)
                return 1;
 
-       if (current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
+       if (current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
                return 1;
 
        return sysctl_legacy_va_layout;
index c936c5c..30c71a0 100644 (file)
@@ -71,6 +71,7 @@ struct op_system_config {
        unsigned long mmcra;
        unsigned long enable_kernel;
        unsigned long enable_user;
+       unsigned long backtrace_spinlocks;
 };
 
 /* Per-arch configuration */
index c61770c..e1fc2ca 100644 (file)
@@ -35,7 +35,7 @@ static struct sysrq_key_op sysrq_xmon_op =
 {
        .handler =      sysrq_handle_xmon,
        .help_msg =     "Xmon",
-       .action_msg =   "Entering xmon\n",
+       .action_msg =   "Entering xmon",
 };
 
 static int __init setup_xmon_sysrq(void)
@@ -173,7 +173,7 @@ xmon_fgets(char *str, int nb, void *f)
                c = xmon_getchar();
                if (c == -1) {
                        if (p == str)
-                               return 0;
+                               return NULL;
                        break;
                }
                *p++ = c;
index 7537972..3f7018e 100644 (file)
@@ -22,6 +22,8 @@ int main(void)
        DEFINE(__THREAD_mm_segment,
               offsetof(struct task_struct, thread.mm_segment),);
        BLANK();
+       DEFINE(__TASK_pid, offsetof(struct task_struct, pid),);
+       BLANK();
        DEFINE(__PER_atmid, offsetof(per_struct, lowcore.words.perc_atmid),);
        DEFINE(__PER_address, offsetof(per_struct, lowcore.words.address),);
        DEFINE(__PER_access_id, offsetof(per_struct, lowcore.words.access_id),);
index d483515..9957926 100644 (file)
@@ -15,7 +15,7 @@
 #include <asm/system.h>
 
 static spinlock_t cpcmd_lock = SPIN_LOCK_UNLOCKED;
-static char cpcmd_buf[128];
+static char cpcmd_buf[240];
 
 void cpcmd(char *cmd, char *response, int rlen)
 {
@@ -24,22 +24,23 @@ void cpcmd(char *cmd, char *response, int rlen)
         int cmdlen;
 
        spin_lock_irqsave(&cpcmd_lock, flags);
-        cmdlen = strlen(cmd);
-        strcpy(cpcmd_buf, cmd);
-        ASCEBC(cpcmd_buf, cmdlen);
+       cmdlen = strlen(cmd);
+       BUG_ON(cmdlen>240);
+       strcpy(cpcmd_buf, cmd);
+       ASCEBC(cpcmd_buf, cmdlen);
 
-        if (response != NULL && rlen > 0) {
+       if (response != NULL && rlen > 0) {
 #ifndef CONFIG_ARCH_S390X
                 asm volatile ("LRA   2,0(%0)\n\t"
                               "LR    4,%1\n\t"
                               "O     4,%4\n\t"
                               "LRA   3,0(%2)\n\t"
                               "LR    5,%3\n\t"
-                              ".long 0x83240008 # Diagnose 83\n\t"
+                              ".long 0x83240008 # Diagnose X'08'\n\t"
                               : /* no output */
                               : "a" (cpcmd_buf), "d" (cmdlen),
                                 "a" (response), "d" (rlen), "m" (mask)
-                              : "2", "3", "4", "5" );
+                              : "cc", "2", "3", "4", "5" );
 #else /* CONFIG_ARCH_S390X */
                 asm volatile ("   lrag  2,0(%0)\n"
                               "   lgr   4,%1\n"
@@ -47,19 +48,19 @@ void cpcmd(char *cmd, char *response, int rlen)
                               "   lrag  3,0(%2)\n"
                               "   lgr   5,%3\n"
                               "   sam31\n"
-                              "   .long 0x83240008 # Diagnose 83\n"
+                              "   .long 0x83240008 # Diagnose X'08'\n"
                               "   sam64"
                               : /* no output */
                               : "a" (cpcmd_buf), "d" (cmdlen),
                                 "a" (response), "d" (rlen), "m" (mask)
-                              : "2", "3", "4", "5" );
+                              : "cc", "2", "3", "4", "5" );
 #endif /* CONFIG_ARCH_S390X */
                 EBCASC(response, rlen);
         } else {
 #ifndef CONFIG_ARCH_S390X
                 asm volatile ("LRA   2,0(%0)\n\t"
                               "LR    3,%1\n\t"
-                              ".long 0x83230008 # Diagnose 83\n\t"
+                              ".long 0x83230008 # Diagnose X'08'\n\t"
                               : /* no output */
                               : "a" (cpcmd_buf), "d" (cmdlen)
                               : "2", "3"  );
@@ -67,7 +68,7 @@ void cpcmd(char *cmd, char *response, int rlen)
                 asm volatile ("   lrag  2,0(%0)\n"
                               "   lgr   3,%1\n"
                               "   sam31\n"
-                              "   .long 0x83230008 # Diagnose 83\n"
+                              "   .long 0x83230008 # Diagnose X'08'\n"
                               "   sam64"
                               : /* no output */
                               : "a" (cpcmd_buf), "d" (cmdlen)
index 79a4222..75275fe 100644 (file)
@@ -86,7 +86,7 @@ asmlinkage void do_softirq(void)
                                     "   la    15,0(%1)\n"
                                     : : "a" (new), "a" (old),
                                         "a" (__do_softirq)
-                                    : "0", "1", "2", "3", "4", "5",
+                                    : "0", "1", "2", "3", "4", "5", "14",
                                       "cc", "memory" );
                } else
                        /* We are already on the async stack. */
index b0b2714..73feefb 100644 (file)
@@ -1,11 +1,10 @@
 /*
- * File...........: arch/s390/mm/dcss.c
- * Author(s)......: Steven Shultz <shultzss@us.ibm.com>
- *                  Carsten Otte <cotte@de.ibm.com>
+ * File...........: arch/s390/mm/extmem.c
+ * Author(s)......: Carsten Otte <cotte@de.ibm.com>
+ *                 Rob M van der Heij <rvdheij@nl.ibm.com>
+ *                 Steven Shultz <shultzss@us.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * thanks to Rob M van der Heij
- * - he wrote the diag64 function
- * (C) IBM Corporation 2002
+ * (C) IBM Corporation 2002-2004
  */
 
 #include <linux/kernel.h>
 #define DCSS_FINDSEG    0x0c
 #define DCSS_LOADNOLY   0x10
 #define DCSS_SEGEXT     0x18
-#define DCSS_QACTV      0x0c
+#define DCSS_FINDSEGA   0x0c
+
+struct qrange {
+       unsigned int  start; // 3byte start address, 1 byte type
+       unsigned int  end;   // 3byte end address, 1 byte reserved
+};
+
+struct qout64 {
+       int segstart;
+       int segend;
+       int segcnt;
+       int segrcnt;
+       struct qrange range[6];
+};
+
+struct qin64 {
+       char qopcode;
+       char rsrv1[3];
+       char qrcode;
+       char rsrv2[3];
+       char qname[8];
+       unsigned int qoutptr;
+       short int qoutlen;
+};
 
 struct dcss_segment {
-        struct list_head list;
-        char dcss_name[8];
-        unsigned long start_addr;
-        unsigned long end;
-        atomic_t ref_count;
-        int dcss_attr;
-       int shared_attr;
+       struct list_head list;
+       char dcss_name[8];
+       unsigned long start_addr;
+       unsigned long end;
+       atomic_t ref_count;
+       int do_nonshared;
+       unsigned int vm_segtype;
+       struct qrange range[6];
+       int segcnt;
 };
 
 static spinlock_t dcss_lock = SPIN_LOCK_UNLOCKED;
 static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list);
+static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
+                                       "EW/EN-MIXED" };
+
 extern struct {
        unsigned long addr, size, type;
 } memory_chunk[MEMORY_CHUNKS];
@@ -63,20 +90,46 @@ extern struct {
  * Create the 8 bytes, ebcdic VM segment name from
  * an ascii name.
  */
-static void inline dcss_mkname(char *name, char *dcss_name)
+static void inline
+dcss_mkname(char *name, char *dcss_name)
+{
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               if (name[i] == '\0')
+                       break;
+               dcss_name[i] = toupper(name[i]);
+       };
+       for (; i < 8; i++)
+               dcss_name[i] = ' ';
+       ASCEBC(dcss_name, 8);
+}
+
+
+/*
+ * search all segments in dcss_list, and return the one
+ * namend *name. If not found, return NULL.
+ */
+static struct dcss_segment *
+segment_by_name (char *name)
 {
-        int i;
-
-        for (i = 0; i <= 8; i++) {
-                if (name[i] == '\0')
-                        break;
-                dcss_name[i] = toupper(name[i]);
-        };
-        for (; i <= 8; i++)
-                dcss_name[i] = ' ';
-        ASCEBC(dcss_name, 8);
+       char dcss_name[9];
+       struct list_head *l;
+       struct dcss_segment *tmp, *retval = NULL;
+
+       BUG_ON (!spin_is_locked(&dcss_lock));
+       dcss_mkname (name, dcss_name);
+       list_for_each (l, &dcss_list) {
+               tmp = list_entry (l, struct dcss_segment, list);
+               if (memcmp(tmp->dcss_name, dcss_name, 8) == 0) {
+                       retval = tmp;
+                       break;
+               }
+       }
+       return retval;
 }
 
+
 /*
  * Perform a function on a dcss segment.
  */
@@ -84,337 +137,378 @@ static inline int
 dcss_diag (__u8 func, void *parameter,
            unsigned long *ret1, unsigned long *ret2)
 {
-        unsigned long rx, ry;
-        int rc;
+       unsigned long rx, ry;
+       int rc;
 
-        rx = (unsigned long) parameter;
-        ry = (unsigned long) func;
-        __asm__ __volatile__(
+       rx = (unsigned long) parameter;
+       ry = (unsigned long) func;
+       __asm__ __volatile__(
 #ifdef CONFIG_ARCH_S390X
-                             "   sam31\n" // switch to 31 bit
-                             "   diag    %0,%1,0x64\n"
-                             "   sam64\n" // switch back to 64 bit
+               "   sam31\n" // switch to 31 bit
+               "   diag    %0,%1,0x64\n"
+               "   sam64\n" // switch back to 64 bit
 #else
-                             "   diag    %0,%1,0x64\n"
+               "   diag    %0,%1,0x64\n"
 #endif
-                             "   ipm     %2\n"
-                             "   srl     %2,28\n"
-                             : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc" );
-        *ret1 = rx;
-        *ret2 = ry;
-        return rc;
+               "   ipm     %2\n"
+               "   srl     %2,28\n"
+               : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc" );
+       *ret1 = rx;
+       *ret2 = ry;
+       return rc;
+}
+
+static inline int
+dcss_diag_translate_rc (int vm_rc) {
+       if (vm_rc == 44)
+               return -ENOENT;
+       return -EIO;
+}
+
+
+/* do a diag to get info about a segment.
+ * fills start_address, end and vm_segtype fields
+ */
+static int
+query_segment_type (struct dcss_segment *seg)
+{
+       struct qin64  *qin = kmalloc (sizeof(struct qin64), GFP_DMA);
+       struct qout64 *qout = kmalloc (sizeof(struct qout64), GFP_DMA);
+
+       int diag_cc, rc, i;
+       unsigned long dummy, vmrc;
+
+       if ((qin == NULL) || (qout == NULL)) {
+               rc = -ENOMEM;
+               goto out_free;
+       }
+
+       /* initialize diag input parameters */
+       qin->qopcode = DCSS_FINDSEGA;
+       qin->qoutptr = (unsigned long) qout;
+       qin->qoutlen = sizeof(struct qout64);
+       memcpy (qin->qname, seg->dcss_name, 8);
+
+       diag_cc = dcss_diag (DCSS_SEGEXT, qin, &dummy, &vmrc);
+
+       if (diag_cc > 1) {
+               rc = dcss_diag_translate_rc (vmrc);
+               goto out_free;
+       }
+
+       if (qout->segcnt > 6) {
+               rc = -ENOTSUPP;
+               goto out_free;
+       }
+
+       if (qout->segcnt == 1) {
+               seg->vm_segtype = qout->range[0].start & 0xff;
+       } else {
+               /* multi-part segment. only one type supported here:
+                   - all parts are contiguous
+                   - all parts are either EW or EN type
+                   - maximum 6 parts allowed */
+               unsigned long start = qout->segstart >> PAGE_SHIFT;
+               for (i=0; i<qout->segcnt; i++) {
+                       if (((qout->range[i].start & 0xff) != SEG_TYPE_EW) &&
+                           ((qout->range[i].start & 0xff) != SEG_TYPE_EN)) {
+                               rc = -ENOTSUPP;
+                               goto out_free;
+                       }
+                       if (start != qout->range[i].start >> PAGE_SHIFT) {
+                               rc = -ENOTSUPP;
+                               goto out_free;
+                       }
+                       start = (qout->range[i].end >> PAGE_SHIFT) + 1;
+               }
+               seg->vm_segtype = SEG_TYPE_EWEN;
+       }
+
+       /* analyze diag output and update seg */
+       seg->start_addr = qout->segstart;
+       seg->end = qout->segend;
+
+       memcpy (seg->range, qout->range, 6*sizeof(struct qrange));
+       seg->segcnt = qout->segcnt;
+
+       rc = 0;
+
+ out_free:
+       if (qin) kfree(qin);
+       if (qout) kfree(qout);
+       return rc;
+}
+
+/*
+ * check if the given segment collides with guest storage.
+ * returns 1 if this is the case, 0 if no collision was found
+ */
+static int
+segment_overlaps_storage(struct dcss_segment *seg)
+{
+       int i;
+
+       for (i=0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+               if (memory_chunk[i].type != 0)
+                       continue;
+               if ((memory_chunk[i].addr >> 20) > (seg->end >> 20))
+                       continue;
+               if (((memory_chunk[i].addr + memory_chunk[i].size - 1) >> 20)
+                               < (seg->start_addr >> 20))
+                       continue;
+               return 1;
+       }
+       return 0;
 }
 
+/*
+ * check if segment collides with other segments that are currently loaded
+ * returns 1 if this is the case, 0 if no collision was found
+ */
+static int
+segment_overlaps_others (struct dcss_segment *seg)
+{
+       struct list_head *l;
+       struct dcss_segment *tmp;
+
+       BUG_ON (!spin_is_locked(&dcss_lock));
+       list_for_each(l, &dcss_list) {
+               tmp = list_entry(l, struct dcss_segment, list);
+               if ((tmp->start_addr >> 20) > (seg->end >> 20))
+                       continue;
+               if ((tmp->end >> 20) < (seg->start_addr >> 20))
+                       continue;
+               if (seg == tmp)
+                       continue;
+               return 1;
+       }
+       return 0;
+}
 
-/* use to issue "extended" dcss query */
+/*
+ * check if segment exceeds the kernel mapping range (detected or set via mem=)
+ * returns 1 if this is the case, 0 if segment fits into the range
+ */
 static inline int
-dcss_diag_query(char *name, int *rwattr, int *shattr, unsigned long *segstart, unsigned long *segend)
+segment_exceeds_range (struct dcss_segment *seg)
 {
-        int i,j,rc;
-        unsigned long  rx, ry;
-
-        typedef struct segentry {
-                char thisseg[8];
-        } segentry;
-
-        struct qout64 {
-                int segstart;
-                int segend;
-                int segcnt;
-                int segrcnt;
-                segentry segout[6];
-        };
-
-        struct qin64 {
-                char qopcode;
-                char rsrv1[3];
-                char qrcode;
-                char rsrv2[3];
-                char qname[8];
-                unsigned int qoutptr;
-                short int qoutlen;
-        };
-
-
-        struct qin64  *qinarea;
-        struct qout64 *qoutarea;
-
-        qinarea = (struct qin64*) get_zeroed_page (GFP_DMA);
-        if (!qinarea) {
-                rc =-ENOMEM;
-                goto out;
-        }
-        qoutarea = (struct qout64*) get_zeroed_page (GFP_DMA);
-        if (!qoutarea) {
-                rc = -ENOMEM;
-                free_page ((unsigned long) qinarea);
-                goto out;
-        }
-        memset (qinarea,0,PAGE_SIZE);
-        memset (qoutarea,0,PAGE_SIZE);
-
-        qinarea->qopcode = DCSS_QACTV; /* do a query for active
-                                          segments */
-        qinarea->qoutptr = (unsigned long) qoutarea;
-        qinarea->qoutlen = sizeof(struct qout64);
-
-        /* Move segment name into double word aligned
-           field and pad with blanks to 8 long.
-         */
-
-        for (i = j = 0 ; i < 8; i++) {
-                qinarea->qname[i] = (name[j] == '\0') ? ' ' : name[j++];
-        }
-
-        /* name already in EBCDIC */
-        /* ASCEBC ((void *)&qinarea.qname, 8); */
-
-        /* set the assembler variables */
-        rx = (unsigned long) qinarea;
-        ry = DCSS_SEGEXT; /* this is extended function */
-
-        /* issue diagnose x'64' */
-        __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                             "   sam31\n" // switch to 31 bit
-                             "   diag    %0,%1,0x64\n"
-                             "   sam64\n" // switch back to 64 bit
-#else
-                             "   diag    %0,%1,0x64\n"
-#endif
-                             "   ipm     %2\n"
-                             "   srl     %2,28\n"
-                             : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc" );
-
-        /* parse the query output area */
-       *segstart=qoutarea->segstart;
-       *segend=qoutarea->segend;
-
-        if (rc > 1)
-                {
-                        *rwattr = 2;
-                        *shattr = 2;
-                        rc = 0;
-                        goto free;
-                }
-
-        if (qoutarea->segcnt > 6)
-                {
-                        *rwattr = 3;
-                        *shattr = 3;
-                        rc = 0;
-                        goto free;
-                }
-
-        *rwattr = 1;
-        *shattr = 1;
-
-        for (i=0; i < qoutarea->segrcnt; i++) {
-                if (qoutarea->segout[i].thisseg[3] == 2 ||
-                    qoutarea->segout[i].thisseg[3] == 3 ||
-                    qoutarea->segout[i].thisseg[3] == 6 )
-                        *rwattr = 0;
-                if (qoutarea->segout[i].thisseg[3] == 1 ||
-                    qoutarea->segout[i].thisseg[3] == 3 ||
-                    qoutarea->segout[i].thisseg[3] == 5 )
-                        *shattr = 0;
-        } /* end of for statement */
-        rc = 0;
- free:
-        free_page ((unsigned long) qoutarea);
-        free_page ((unsigned long) qinarea);
+       int seg_last_pfn = (seg->end) >> PAGE_SHIFT;
+       if (seg_last_pfn > max_pfn)
+               return 1;
+       return 0;
+}
+
+/*
+ * get info about a segment
+ * possible return values:
+ * -ENOSYS  : we are not running on VM
+ * -EIO     : could not perform query diagnose
+ * -ENOENT  : no such segment
+ * -ENOTSUPP: multi-part segment cannot be used with linux
+ * -ENOSPC  : segment cannot be used (overlaps with storage)
+ * -ENOMEM  : out of memory
+ * 0 .. 6   : type of segment as defined in include/asm-s390/extmem.h
+ */
+int
+segment_type (char* name)
+{
+       int rc;
+       struct dcss_segment seg;
+
+       if (!MACHINE_IS_VM)
+               return -ENOSYS;
+
+       dcss_mkname(name, seg.dcss_name);
+       rc = query_segment_type (&seg);
+       if (rc < 0)
+               return rc;
+       return seg.vm_segtype;
+}
+
+/*
+ * real segment loading function, called from segment_load
+ */
+static int
+__segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end)
+{
+       struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment),
+                       GFP_DMA);
+       int dcss_command, rc, diag_cc;
+
+       if (seg == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+       dcss_mkname (name, seg->dcss_name);
+       rc = query_segment_type (seg);
+       if (rc < 0)
+               goto out_free;
+       if (segment_exceeds_range(seg)) {
+               PRINT_WARN ("segment_load: not loading segment %s - exceeds"
+                               " kernel mapping range\n",name);
+               rc = -ERANGE;
+               goto out_free;
+       }
+       if (segment_overlaps_storage(seg)) {
+               PRINT_WARN ("segment_load: not loading segment %s - overlaps"
+                               " storage\n",name);
+               rc = -ENOSPC;
+               goto out_free;
+       }
+       if (segment_overlaps_others(seg)) {
+               PRINT_WARN ("segment_load: not loading segment %s - overlaps"
+                               " other segments\n",name);
+               rc = -EBUSY;
+               goto out_free;
+       }
+       if (do_nonshared)
+               dcss_command = DCSS_LOADNSR;
+       else
+               dcss_command = DCSS_LOADNOLY;
+
+       diag_cc = dcss_diag(dcss_command, seg->dcss_name,
+                       &seg->start_addr, &seg->end);
+       if (diag_cc > 1) {
+               PRINT_WARN ("segment_load: could not load segment %s - "
+                               "diag returned error (%ld)\n",name,seg->end);
+               rc = dcss_diag_translate_rc (seg->end);
+               dcss_diag(DCSS_PURGESEG, seg->dcss_name,
+                               &seg->start_addr, &seg->end);
+               goto out_free;
+       }
+       seg->do_nonshared = do_nonshared;
+       atomic_set(&seg->ref_count, 1);
+       list_add(&seg->list, &dcss_list);
+       rc = seg->vm_segtype;
+       *addr = seg->start_addr;
+       *end  = seg->end;
+       if (do_nonshared)
+               PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
+                               "type %s in non-shared mode\n", name,
+                               (void*)seg->start_addr, (void*)seg->end,
+                               segtype_string[seg->vm_segtype]);
+       else
+               PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
+                               "type %s in shared mode\n", name,
+                               (void*)seg->start_addr, (void*)seg->end,
+                               segtype_string[seg->vm_segtype]);
+       goto out;
+ out_free:
+       kfree (seg);
  out:
-        return rc;
+       return rc;
 }
 
 /*
- * Load a DCSS segment via the diag 0x64.
+ * this function loads a DCSS segment
+ * name         : name of the DCSS
+ * do_nonshared : 0 indicates that the dcss should be shared with other linux images
+ *                1 indicates that the dcss should be exclusive for this linux image
+ * addr         : will be filled with start address of the segment
+ * end          : will be filled with end address of the segment
+ * return values:
+ * -ENOSYS  : we are not running on VM
+ * -EIO     : could not perform query or load diagnose
+ * -ENOENT  : no such segment
+ * -ENOTSUPP: multi-part segment cannot be used with linux
+ * -ENOSPC  : segment cannot be used (overlaps with storage)
+ * -EBUSY   : segment can temporarily not be used (overlaps with dcss)
+ * -ERANGE  : segment cannot be used (exceeds kernel mapping range)
+ * -EPERM   : segment is currently loaded with incompatible permissions
+ * -ENOMEM  : out of memory
+ * 0 .. 6   : type of segment as defined in include/asm-s390/extmem.h
  */
-int segment_load(char *name, int segtype, unsigned long *addr,
-                 unsigned long *end)
+int
+segment_load (char *name, int do_nonshared, unsigned long *addr,
+               unsigned long *end)
 {
-        char dcss_name[8];
-        struct list_head *l;
-        struct dcss_segment *seg, *tmp;
-       unsigned long dummy;
-       unsigned long segstart, segend;
-        int rc = 0,i;
-        int rwattr, shattr;
-
-        if (!MACHINE_IS_VM)
-                return -ENOSYS;
-        dcss_mkname(name, dcss_name);
-       /* search for the dcss in list of currently loaded segments */
-        spin_lock(&dcss_lock);
-        seg = NULL;
-        list_for_each(l, &dcss_list) {
-                tmp = list_entry(l, struct dcss_segment, list);
-                if (memcmp(tmp->dcss_name, dcss_name, 8) == 0) {
-                        seg = tmp;
-                        break;
-                }
-        }
-
-        if (seg == NULL) {
-                /* find out the attributes of this
-                   shared segment */
-                dcss_diag_query(dcss_name, &rwattr, &shattr, &segstart, &segend);
-               /* does segment collide with main memory? */
-               for (i=0; i < MEMORY_CHUNKS; i++) {
-                       if (memory_chunk[i].type != 0)
-                               continue;
-                       if (memory_chunk[i].addr > segend)
-                               continue;
-                       if (memory_chunk[i].addr + memory_chunk[i].size <= segstart)
-                               continue;
-                       spin_unlock(&dcss_lock);
-                       return -ENOENT;
-               }
-               /* or does it collide with other (loaded) segments? */
-               list_for_each(l, &dcss_list) {
-                       tmp = list_entry(l, struct dcss_segment, list);
-                       if ((segstart <= tmp->end && segstart >= tmp->start_addr) ||
-                               (segend <= tmp->end && segend >= tmp->start_addr) ||
-                               (segstart <= tmp->start_addr && segend >= tmp->end)) {
-                               PRINT_ERR("Segment Overlap!\n");
-                               spin_unlock(&dcss_lock);
-                               return -ENOENT;
-                       }
-               }
-
-                /* do case statement on segtype */
-                /* if asking for shared ro,
-                   shared rw works */
-                /* if asking for exclusive ro,
-                   exclusive rw works */
-
-                switch(segtype) {
-                case SEGMENT_SHARED_RO:
-                        if (shattr > 1 || rwattr > 1) {
-                                spin_unlock(&dcss_lock);
-                                return -ENOENT;
-                        } else {
-                                if (shattr == 0 && rwattr == 0)
-                                        rc = SEGMENT_EXCLUSIVE_RO;
-                                if (shattr == 0 && rwattr == 1)
-                                        rc = SEGMENT_EXCLUSIVE_RW;
-                                if (shattr == 1 && rwattr == 0)
-                                        rc = SEGMENT_SHARED_RO;
-                                if (shattr == 1 && rwattr == 1)
-                                        rc = SEGMENT_SHARED_RW;
-                        }
-                        break;
-                case SEGMENT_SHARED_RW:
-                        if (shattr > 1 || rwattr != 1) {
-                                spin_unlock(&dcss_lock);
-                                return -ENOENT;
-                        } else {
-                                if (shattr == 0)
-                                        rc = SEGMENT_EXCLUSIVE_RW;
-                                if (shattr == 1)
-                                        rc = SEGMENT_SHARED_RW;
-                        }
-                        break;
-
-                case SEGMENT_EXCLUSIVE_RO:
-                        if (shattr > 0 || rwattr > 1) {
-                                spin_unlock(&dcss_lock);
-                                return -ENOENT;
-                        } else {
-                                if (rwattr == 0)
-                                        rc = SEGMENT_EXCLUSIVE_RO;
-                                if (rwattr == 1)
-                                        rc = SEGMENT_EXCLUSIVE_RW;
-                        }
-                        break;
-
-                case SEGMENT_EXCLUSIVE_RW:
-/*                        if (shattr != 0 || rwattr != 1) {
-                                spin_unlock(&dcss_lock);
-                                return -ENOENT;
-                        } else {
-*/
-                                rc = SEGMENT_EXCLUSIVE_RW;
-//                        }
-                        break;
-
-                default:
-                        spin_unlock(&dcss_lock);
-                        return -ENOENT;
-                } /* end switch */
-
-                seg = kmalloc(sizeof(struct dcss_segment), GFP_DMA);
-                if (seg != NULL) {
-                        memcpy(seg->dcss_name, dcss_name, 8);
-                       if (rc == SEGMENT_EXCLUSIVE_RW) {
-                               if (dcss_diag(DCSS_LOADNSR, seg->dcss_name,
-                                               &seg->start_addr, &seg->end) == 0) {
-                                       if (seg->end < max_low_pfn*PAGE_SIZE ) {
-                                               atomic_set(&seg->ref_count, 1);
-                                               list_add(&seg->list, &dcss_list);
-                                               *addr = seg->start_addr;
-                                               *end = seg->end;
-                                               seg->dcss_attr = rc;
-                                               if (shattr == 1 && rwattr == 1)
-                                                       seg->shared_attr = SEGMENT_SHARED_RW;
-                                               else if (shattr == 1 && rwattr == 0)
-                                                       seg->shared_attr = SEGMENT_SHARED_RO;
-                                               else
-                                                       seg->shared_attr = SEGMENT_EXCLUSIVE_RW;
-                                       } else {
-                                               dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
-                                               kfree (seg);
-                                               rc = -ENOENT;
-                                       }
-                               } else {
-                                       kfree(seg);
-                                       rc = -ENOENT;
-                               }
-                               goto out;
-                        }
-                       if (dcss_diag(DCSS_LOADNOLY, seg->dcss_name,
-                                      &seg->start_addr, &seg->end) == 0) {
-                               if (seg->end < max_low_pfn*PAGE_SIZE ) {
-                                       atomic_set(&seg->ref_count, 1);
-                                       list_add(&seg->list, &dcss_list);
-                                       *addr = seg->start_addr;
-                                       *end = seg->end;
-                                       seg->dcss_attr = rc;
-                                       seg->shared_attr = rc;
-                               } else {
-                                       dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
-                                       kfree (seg);
-                                       rc = -ENOENT;
-                               }
-                        } else {
-                                kfree(seg);
-                                rc = -ENOENT;
-                        }
-                } else rc = -ENOMEM;
-        } else {
-               /* found */
-               if ((segtype == SEGMENT_EXCLUSIVE_RW) && (seg->dcss_attr != SEGMENT_EXCLUSIVE_RW)) {
-                       PRINT_ERR("Segment already loaded in other mode than EXCLUSIVE_RW!\n");
-                       rc = -EPERM;
-                       goto out;
-                       /* reload segment in exclusive mode */
-/*                     dcss_diag(DCSS_LOADNSR, seg->dcss_name,
-                                 &seg->start_addr, &seg->end);
-                       seg->dcss_attr = SEGMENT_EXCLUSIVE_RW;*/
+       struct dcss_segment *seg;
+       int rc;
+
+       if (!MACHINE_IS_VM)
+               return -ENOSYS;
+
+       spin_lock (&dcss_lock);
+       seg = segment_by_name (name);
+       if (seg == NULL)
+               rc = __segment_load (name, do_nonshared, addr, end);
+       else {
+               if (do_nonshared == seg->do_nonshared) {
+                       atomic_inc(&seg->ref_count);
+                       *addr = seg->start_addr;
+                       *end  = seg->end;
+                       rc    = seg->vm_segtype;
+               } else {
+                       *addr = *end = 0;
+                       rc    = -EPERM;
                }
-               if ((segtype != SEGMENT_EXCLUSIVE_RW) && (seg->dcss_attr == SEGMENT_EXCLUSIVE_RW)) {
-                       PRINT_ERR("Segment already loaded in EXCLUSIVE_RW mode!\n");
-                       rc = -EPERM;
-                       goto out;
-               }
-                atomic_inc(&seg->ref_count);
-                *addr = seg->start_addr;
-                *end = seg->end;
-                rc = seg->dcss_attr;
-        }
-out:
-        spin_unlock(&dcss_lock);
-        return rc;
+       }
+       spin_unlock (&dcss_lock);
+       return rc;
+}
+
+/*
+ * this function modifies the shared state of a DCSS segment. note that
+ * name         : name of the DCSS
+ * do_nonshared : 0 indicates that the dcss should be shared with other linux images
+ *                1 indicates that the dcss should be exclusive for this linux image
+ * return values:
+ * -EIO     : could not perform load diagnose (segment gone!)
+ * -ENOENT  : no such segment (segment gone!)
+ * -EAGAIN  : segment is in use by other exploiters, try later
+ * -EINVAL  : no segment with the given name is currently loaded - name invalid
+ * 0       : operation succeeded
+ */
+int
+segment_modify_shared (char *name, int do_nonshared)
+{
+       struct dcss_segment *seg;
+       unsigned long dummy;
+       int dcss_command, rc, diag_cc;
+
+       spin_lock (&dcss_lock);
+       seg = segment_by_name (name);
+       if (seg == NULL) {
+               rc = -EINVAL;
+               goto out_unlock;
+       }
+       if (do_nonshared == seg->do_nonshared) {
+               PRINT_INFO ("segment_modify_shared: not reloading segment %s"
+                               " - already in requested mode\n",name);
+               rc = 0;
+               goto out_unlock;
+       }
+       if (atomic_read (&seg->ref_count) != 1) {
+               PRINT_WARN ("segment_modify_shared: not reloading segment %s - "
+                               "segment is in use by other driver(s)\n",name);
+               rc = -EAGAIN;
+               goto out_unlock;
+       }
+       dcss_diag(DCSS_PURGESEG, seg->dcss_name,
+                 &dummy, &dummy);
+       if (do_nonshared)
+               dcss_command = DCSS_LOADNSR;
+       else
+       dcss_command = DCSS_LOADNOLY;
+       diag_cc = dcss_diag(dcss_command, seg->dcss_name,
+                       &seg->start_addr, &seg->end);
+       if (diag_cc > 1) {
+               PRINT_WARN ("segment_modify_shared: could not reload segment %s"
+                               " - diag returned error (%ld)\n",name,seg->end);
+               rc = dcss_diag_translate_rc (seg->end);
+               goto out_del;
+       }
+       seg->do_nonshared = do_nonshared;
+       rc = 0;
+       goto out_unlock;
+ out_del:
+       list_del(&seg->list);
+       dcss_diag(DCSS_PURGESEG, seg->dcss_name,
+                 &dummy, &dummy);
+       kfree (seg);
+ out_unlock:
+       spin_unlock(&dcss_lock);
+       return rc;
 }
 
 /*
@@ -422,84 +516,72 @@ out:
  * it from the address space if nobody is using it
  * any longer.
  */
-void segment_unload(char *name)
+void
+segment_unload(char *name)
 {
-        char dcss_name[8];
-        unsigned long dummy;
-        struct list_head *l,*l_tmp;
-        struct dcss_segment *seg;
-
-        if (!MACHINE_IS_VM)
-                return;
-        dcss_mkname(name, dcss_name);
-        spin_lock(&dcss_lock);
-        list_for_each_safe(l, l_tmp, &dcss_list) {
-                seg = list_entry(l, struct dcss_segment, list);
-                if (memcmp(seg->dcss_name, dcss_name, 8) == 0) {
-                        if (atomic_dec_return(&seg->ref_count) == 0) {
-                                /* Last user of the segment is
-                                   gone. */
-                                list_del(&seg->list);
-                                dcss_diag(DCSS_PURGESEG, seg->dcss_name,
-                                          &dummy, &dummy);
-                               kfree(seg);
-                        }
-                        break;
-                }
-        }
-        spin_unlock(&dcss_lock);
+       unsigned long dummy;
+       struct dcss_segment *seg;
+
+       if (!MACHINE_IS_VM)
+               return;
+
+       spin_lock(&dcss_lock);
+       seg = segment_by_name (name);
+       if (seg == NULL) {
+               PRINT_ERR ("could not find segment %s in segment_unload, "
+                               "please report to linux390@de.ibm.com\n",name);
+               goto out_unlock;
+       }
+       if (atomic_dec_return(&seg->ref_count) == 0) {
+               list_del(&seg->list);
+               dcss_diag(DCSS_PURGESEG, seg->dcss_name,
+                         &dummy, &dummy);
+               kfree(seg);
+       }
+out_unlock:
+       spin_unlock(&dcss_lock);
 }
 
 /*
- * Replace an existing DCSS segment, so that machines
- * that load it anew will see the new version.
+ * save segment content permanently
  */
-void segment_replace(char *name)
+void segment_save(char *name)
 {
-        char dcss_name[8];
-        struct list_head *l;
-        struct dcss_segment *seg;
-        int mybeg = 0;
-        int myend = 0;
-        char mybuff1[80];
-        char mybuff2[80];
-
-        if (!MACHINE_IS_VM)
-                return;
-        dcss_mkname(name, dcss_name);
-
-        memset (mybuff1, 0, sizeof(mybuff1));
-        memset (mybuff2, 0, sizeof(mybuff2));
-
-        spin_lock(&dcss_lock);
-        list_for_each(l, &dcss_list) {
-                seg = list_entry(l, struct dcss_segment, list);
-                if (memcmp(seg->dcss_name, dcss_name, 8) == 0) {
-                        mybeg = seg->start_addr >> 12;
-                        myend = (seg->end) >> 12;
-                        if (seg->shared_attr == SEGMENT_EXCLUSIVE_RW)
-                                sprintf(mybuff1, "DEFSEG %s %X-%X EW",
-                                        name, mybeg, myend);
-                        if (seg->shared_attr == SEGMENT_EXCLUSIVE_RO)
-                                sprintf(mybuff1, "DEFSEG %s %X-%X RO",
-                                        name, mybeg, myend);
-                        if (seg->shared_attr == SEGMENT_SHARED_RW)
-                                sprintf(mybuff1, "DEFSEG %s %X-%X SW",
-                                        name, mybeg, myend);
-                        if (seg->shared_attr == SEGMENT_SHARED_RO)
-                                sprintf(mybuff1, "DEFSEG %s %X-%X SR",
-                                        name, mybeg, myend);
-                        spin_unlock(&dcss_lock);
-                        sprintf(mybuff2, "SAVESEG %s", name);
-                        cpcmd(mybuff1, NULL, 80);
-                        cpcmd(mybuff2, NULL, 80);
-                        break;
-                }
-
-        }
-        if (myend == 0) spin_unlock(&dcss_lock);
+       struct dcss_segment *seg;
+       int startpfn = 0;
+       int endpfn = 0;
+       char cmd1[160];
+       char cmd2[80];
+       int i;
+
+       if (!MACHINE_IS_VM)
+               return;
+
+       spin_lock(&dcss_lock);
+       seg = segment_by_name (name);
+
+       if (seg == NULL) {
+               PRINT_ERR ("could not find segment %s in segment_save, please report to linux390@de.ibm.com\n",name);
+               return;
+       }
+
+       startpfn = seg->start_addr >> PAGE_SHIFT;
+       endpfn = (seg->end) >> PAGE_SHIFT;
+       sprintf(cmd1, "DEFSEG %s", name);
+       for (i=0; i<seg->segcnt; i++) {
+               sprintf(cmd1+strlen(cmd1), " %X-%X %s",
+                       seg->range[i].start >> PAGE_SHIFT,
+                       seg->range[i].end >> PAGE_SHIFT,
+                       segtype_string[seg->range[i].start & 0xff]);
+       }
+       sprintf(cmd2, "SAVESEG %s", name);
+       cpcmd(cmd1, NULL, 80);
+       cpcmd(cmd2, NULL, 80);
+       spin_unlock(&dcss_lock);
 }
 
 EXPORT_SYMBOL(segment_load);
 EXPORT_SYMBOL(segment_unload);
-EXPORT_SYMBOL(segment_replace);
+EXPORT_SYMBOL(segment_save);
+EXPORT_SYMBOL(segment_type);
+EXPORT_SYMBOL(segment_modify_shared);
index 0824724..c188fc3 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/bitops.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 
 #include <asm/bigsur/io.h>
 #include <asm/hd64465/hd64465.h>
index 9cb3292..e69be05 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/bitops.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/machvec.h>
 #include <asm/bigsur/io.h>
 #include <asm/hd64465/hd64465.h>
index c59d159..55dece3 100644 (file)
@@ -1,15 +1,15 @@
-/* 
+/*
  * arch/sh/boards/dreamcast/setup.c
  *
  * Hardware support for the Sega Dreamcast.
  *
  * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@linuxdc.org>
- * Copyright (c) 2002, 2003 Paul Mundt <lethal@linux-sh.org>
+ * Copyright (c) 2002, 2003, 2004 Paul Mundt <lethal@linux-sh.org>
  *
  * This file is part of the LinuxDC project (www.linuxdc.org)
  *
  * Released under the terms of the GNU GPL v2.0.
- * 
+ *
  * This file originally bore the message (with enclosed-$):
  *     Id: setup_dc.c,v 1.5 2001/05/24 05:09:16 mrbrown Exp
  *     SEGA Dreamcast support
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -34,6 +35,10 @@ extern void (*board_time_init)(void);
 extern void aica_time_init(void);
 extern int gapspci_init(void);
 extern int systemasic_irq_demux(int);
+
+void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, int);
+int dreamcast_consistent_free(struct device *, size_t, void *, dma_addr_t);
+
 const char *get_system_type(void)
 {
        return "Sega Dreamcast";
@@ -43,6 +48,11 @@ struct sh_machine_vector mv_dreamcast __initmv = {
        .mv_nr_irqs             = NR_IRQS,
 
        .mv_irq_demux           = systemasic_irq_demux,
+
+#ifdef CONFIG_PCI
+       .mv_consistent_alloc    = dreamcast_consistent_alloc,
+       .mv_consistent_free     = dreamcast_consistent_free,
+#endif
 };
 ALIAS_MV(dreamcast)
 
index 0d64b28..05b01b8 100644 (file)
@@ -54,3 +54,38 @@ int __init platform_setup(void)
 
        return 0;
 }
+
+/*
+ * pcibios_map_platform_irq
+ *
+ * This is board specific and returns the IRQ for a given PCI device.
+ * It is used by the PCI code (arch/sh/kernel/st40_pci*)
+ *
+ */
+
+#define HARP_PCI_IRQ    1
+#define HARP_BRIDGE_IRQ 2
+#define OVERDRIVE_SLOT0_IRQ 0
+
+
+int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       switch (slot) {
+#ifdef CONFIG_SH_STB1_HARP
+       case 2:         /*This is the PCI slot on the */
+               return HARP_PCI_IRQ;
+       case 1:         /* this is the bridge */
+               return HARP_BRIDGE_IRQ;
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+       case 1:
+       case 2:
+       case 3:
+               return slot - 1;
+#else
+#error Unknown board
+#endif
+       default:
+               return -1;
+       }
+}
+
index 275ea1a..1c9bfed 100644 (file)
@@ -25,7 +25,7 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
 
         printk("BUG: pci_alloc_consistent() called - not yet supported\n");
        /* We ALWAYS need DMA memory on the overdrive hardware,
-        * due to it's extreme wierdness
+        * due to it's extreme weirdness
         * Need to flush the cache here as well, since the memory
         * can still be seen through the cache!
         */
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 .. */
+}
+
index c1ff454..1efc18e 100644 (file)
@@ -24,7 +24,7 @@ extern void *rts7751r2d_ioremap(unsigned long, unsigned long);
 extern int rts7751r2d_irq_demux(int irq);
 
 extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, int);
-extern void voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
+extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
 
 /*
  * The Machine Vector
@@ -62,7 +62,9 @@ struct sh_machine_vector mv_rts7751r2d __initmv = {
 #endif
        .mv_irq_demux           = rts7751r2d_irq_demux,
 
+#ifdef CONFIG_USB_OHCI_HCD
        .mv_consistent_alloc    = voyagergx_consistent_alloc,
        .mv_consistent_free     = voyagergx_consistent_free,
+#endif
 };
 ALIAS_MV(rts7751r2d)
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)
+{
+
+}
index dff4fbd..210897b 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: irq.c,v 1.4 2004/02/22 22:44:36 kkojima Exp $
- * 
+/*
  * linux/arch/sh/boards/se/770x/irq.c
  *
  * Copyright (C) 2000  Kazumoto Kojima
@@ -12,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <asm/irq.h>
+#include <asm/io.h>
 #include <asm/se/se.h>
 
 /*
@@ -30,6 +30,32 @@ void __init init_se_IRQ(void)
          * 12: mouse
          * 14: ide0
          */
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+       /* Disable all interrupts */
+       ctrl_outw(0, BCR_ILCRA);
+       ctrl_outw(0, BCR_ILCRB);
+       ctrl_outw(0, BCR_ILCRC);
+       ctrl_outw(0, BCR_ILCRD);
+       ctrl_outw(0, BCR_ILCRE);
+       ctrl_outw(0, BCR_ILCRF);
+       ctrl_outw(0, BCR_ILCRG);
+       /* This is default value */
+       make_ipr_irq(0xf-0x2, BCR_ILCRA, 2, 0x2);
+       make_ipr_irq(0xf-0xa, BCR_ILCRA, 1, 0xa);
+       make_ipr_irq(0xf-0x5, BCR_ILCRB, 0, 0x5);
+       make_ipr_irq(0xf-0x8, BCR_ILCRC, 1, 0x8);
+       make_ipr_irq(0xf-0xc, BCR_ILCRC, 0, 0xc);
+       make_ipr_irq(0xf-0xe, BCR_ILCRD, 3, 0xe);
+       make_ipr_irq(0xf-0x3, BCR_ILCRD, 1, 0x3); /* LAN */
+       make_ipr_irq(0xf-0xd, BCR_ILCRE, 2, 0xd);
+       make_ipr_irq(0xf-0x9, BCR_ILCRE, 1, 0x9);
+       make_ipr_irq(0xf-0x1, BCR_ILCRE, 0, 0x1);
+       make_ipr_irq(0xf-0xf, BCR_ILCRF, 3, 0xf);
+       make_ipr_irq(0xf-0xb, BCR_ILCRF, 1, 0xb);
+       make_ipr_irq(0xf-0x7, BCR_ILCRG, 3, 0x7);
+       make_ipr_irq(0xf-0x6, BCR_ILCRG, 2, 0x6);
+       make_ipr_irq(0xf-0x4, BCR_ILCRG, 1, 0x4);
+#else
         make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
         make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
         make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
@@ -50,4 +76,5 @@ void __init init_se_IRQ(void)
         /* NOTE: #2 and #13 are not used on PC */
         make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
         make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
+#endif
 }
index aa5dde2..f9b4c56 100644 (file)
@@ -33,6 +33,8 @@ struct sh_machine_vector mv_se __initmv = {
        .mv_nr_irqs             = 32,
 #elif defined(CONFIG_CPU_SUBTYPE_SH7709)
        .mv_nr_irqs             = 61,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+       .mv_nr_irqs             = 86,
 #endif
 
        .mv_inb                 = se_inb,
index 224a5e3..99041b2 100644 (file)
@@ -18,7 +18,7 @@
 #include <asm/addrspace.h>
 
 #include <linux/pci.h>
-#include <asm/pci-sh7751.h>
+#include "../../../drivers/pci/pci-sh7751.h"
 
 #if 0
 /******************************************************************
index 2f8682e..1f273ef 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/pci.h>
 
 #include <asm/io.h>
-#include <asm/pci-sh7751.h>
+#include "../../../drivers/pci/pci-sh7751.h"
 
 #define PCIMCR_MRSET_OFF       0xBFFFFFFF
 #define PCIMCR_RFSH_OFF                0xFFFFFFFB
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
index b724a51..34fd8d1 100644 (file)
@@ -18,9 +18,12 @@ CONFIG_BROKEN_ON_SMP=y
 #
 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
@@ -29,6 +32,8 @@ 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
@@ -44,6 +49,7 @@ CONFIG_OBSOLETE_MODPARM=y
 #
 # 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_7751_SYSTEMH is not set
 # CONFIG_SH_STB1_HARP is not set
 # CONFIG_SH_STB1_OVERDRIVE is not set
@@ -61,6 +67,7 @@ CONFIG_OBSOLETE_MODPARM=y
 # 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=y
 # CONFIG_SH_UNKNOWN is not set
 # CONFIG_CPU_SH2 is not set
@@ -68,6 +75,7 @@ CONFIG_SH_RTS7751R2D=y
 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
@@ -75,6 +83,7 @@ CONFIG_CPU_SH4=y
 CONFIG_CPU_SUBTYPE_SH7751=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
 CONFIG_MMU=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="mem=64M console=ttySC0,115200 root=/dev/hda1"
@@ -92,14 +101,29 @@ CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_SH_OCRAM is not set
 # CONFIG_SH_STORE_QUEUES is not set
 # CONFIG_SMP is not set
-CONFIG_VOYAGERGX=y
 CONFIG_RTS7751R2D_REV11=y
+CONFIG_SH_PCLK_CALC=y
 CONFIG_SH_PCLK_FREQ=60000000
+
+#
+# CPU Frequency scaling
+#
 # CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
 CONFIG_SH_DMA=y
 CONFIG_NR_ONCHIP_DMA_CHANNELS=8
 # CONFIG_NR_DMA_CHANNELS_BOOL is not set
-# CONFIG_DMA_PAGE_OPS is not set
+
+#
+# Companion Chips
+#
+CONFIG_VOYAGERGX=y
+# CONFIG_HD6446X_SERIES is not set
+CONFIG_HEARTBEAT=y
+CONFIG_RTC_9701JE=y
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -109,15 +133,14 @@ CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
 CONFIG_PCI_AUTO=y
 CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-CONFIG_PCI_DMA=y
 # CONFIG_PCI_LEGACY_PROC is not set
 CONFIG_PCI_NAMES=y
-CONFIG_HOTPLUG=y
 
 #
 # PCMCIA/CardBus support
 #
 CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_DEBUG is not set
 CONFIG_YENTA=m
 CONFIG_CARDBUS=y
 # CONFIG_I82092 is not set
@@ -131,6 +154,8 @@ CONFIG_PCMCIA_PROBE=y
 CONFIG_HOTPLUG_PCI=y
 # 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
@@ -139,6 +164,10 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
+#
+# Device Drivers
+#
+
 #
 # Generic Driver Options
 #
@@ -154,6 +183,11 @@ CONFIG_BINFMT_ELF=y
 #
 # CONFIG_PARPORT is not set
 
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
 #
 # Block devices
 #
@@ -165,6 +199,7 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
@@ -174,6 +209,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # ATA/ATAPI/MFM/RLL support
 #
 CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -181,7 +217,6 @@ CONFIG_BLK_DEV_IDE=y
 #
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
 CONFIG_BLK_DEV_IDECS=m
 # CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -192,11 +227,13 @@ CONFIG_BLK_DEV_IDECS=m
 #
 # 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_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -215,10 +252,19 @@ CONFIG_BLK_DEV_IDECS=m
 # CONFIG_MD is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
 #
 # Networking support
 #
@@ -239,23 +285,21 @@ CONFIG_INET=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-# CONFIG_INET_ECN 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_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # 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
@@ -264,6 +308,7 @@ CONFIG_IPV6_SCTP__=y
 # 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
 
 #
@@ -275,16 +320,21 @@ CONFIG_IPV6_SCTP__=y
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY 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
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -325,6 +375,7 @@ CONFIG_NET_PCI=y
 # 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
@@ -355,7 +406,6 @@ CONFIG_8139TOO=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 
@@ -363,10 +413,12 @@ CONFIG_8139TOO=y
 # Ethernet (10000 Mbit)
 #
 # CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
 
 #
 # Wireless LAN (non-hamradio)
@@ -395,27 +447,20 @@ CONFIG_HERMES=m
 # CONFIG_PLX_HERMES is not set
 # CONFIG_TMD_HERMES is not set
 # CONFIG_PCI_HERMES is not set
+# CONFIG_ATMEL is not set
 
 #
 # Wireless 802.11b Pcmcia/Cardbus cards support
 #
 CONFIG_PCMCIA_HERMES=m
 # CONFIG_AIRO_CS is not set
-# CONFIG_PCMCIA_ATMEL is not set
 # CONFIG_PCMCIA_WL3501 is not set
-CONFIG_NET_WIRELESS=y
 
 #
-# Token Ring devices
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
 #
-# CONFIG_TR is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
+# CONFIG_PRISM54 is not set
+CONFIG_NET_WIRELESS=y
 
 #
 # PCMCIA network device support
@@ -423,24 +468,20 @@ CONFIG_NET_WIRELESS=y
 # CONFIG_NET_PCMCIA is not set
 
 #
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
+# Wan interfaces
 #
-# CONFIG_BT is not set
+# 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_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -472,28 +513,7 @@ CONFIG_SOUND_GAMEPORT=y
 # Character devices
 #
 # CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-CONFIG_RTC_9701JE=y
-
-#
-# Unix 98 PTY support
-#
-# CONFIG_UNIX98_PTYS is not set
-CONFIG_HEARTBEAT=y
-# CONFIG_PSMOUSE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_SYNCLINK_CS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
 
 #
 # Serial drivers
@@ -504,142 +524,47 @@ CONFIG_HEARTBEAT=y
 # Non-8250 serial port support
 #
 # CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
 
 #
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Algorithms
-#
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR 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=y
-# 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
+# IPMI
 #
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-# CONFIG_NTFS_FS is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
-# Pseudo filesystems
+# Watchdog Cards
 #
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_TMPFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
+# 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
 
 #
-# Miscellaneous filesystems
+# Ftape, the floppy tape device driver
 #
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_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
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
 
 #
-# Network File Systems
+# PCMCIA character devices
 #
-# CONFIG_NFS_FS is not set
-# CONFIG_NFSD is not set
-# CONFIG_EXPORTFS 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_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
-# Partition Types
+# I2C support
 #
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
+# CONFIG_I2C is not set
 
 #
-# Native Language Support
+# Misc devices
 #
-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=y
-# 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_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
 
 #
 # Multimedia devices
@@ -665,14 +590,21 @@ CONFIG_SOUND=y
 # 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 is not set
-# CONFIG_SND_OSSEMUL is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
 #
 # Generic devices
 #
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_MTPAV is not set
 # CONFIG_SND_SERIAL_U16550 is not set
@@ -707,12 +639,19 @@ CONFIG_SND=m
 #
 # PCI devices
 #
+CONFIG_SND_AC97_CODEC=m
 # CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP 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 is not set
 # 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
@@ -731,6 +670,7 @@ CONFIG_SND_YMFPCI=m
 # 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
@@ -740,6 +680,7 @@ CONFIG_SND_YMFPCI=m
 #
 # CONFIG_SND_VXPOCKET is not set
 # CONFIG_SND_VXP440 is not set
+# CONFIG_SND_PDAUDIOCF is not set
 
 #
 # Open Sound System
@@ -747,10 +688,6 @@ CONFIG_SND_YMFPCI=m
 CONFIG_SOUND_PRIME=m
 # CONFIG_SOUND_BT878 is not set
 CONFIG_SOUND_CMPCI=m
-# CONFIG_SOUND_CMPCI_FM is not set
-# CONFIG_SOUND_CMPCI_MIDI is not set
-# CONFIG_SOUND_CMPCI_JOYSTICK is not set
-# CONFIG_SOUND_CMPCI_CM8738 is not set
 # CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
@@ -776,19 +713,146 @@ CONFIG_SOUND_VOYAGERGX=m
 # 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 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=y
+# 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_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_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_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 is not set
+# CONFIG_NFSD is not set
+# CONFIG_EXPORTFS 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=y
+# 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_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
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
 
 #
 # 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_EARLY_SCIF_CONSOLE is not set
 # CONFIG_KGDB is not set
 # CONFIG_FRAME_POINTER is not set
 
@@ -806,3 +870,4 @@ CONFIG_SOUND_VOYAGERGX=m
 # Library routines
 #
 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
index 4162d3d..6501d94 100644 (file)
@@ -284,6 +284,7 @@ CONFIG_IPV6_SCTP__=y
 # 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
 
 #
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
index f369e6c..231e3f6 100644 (file)
@@ -3,7 +3,7 @@
  *
  * G2 bus DMA support
  *
- * Copyright (C) 2003  Paul Mundt
+ * 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
@@ -59,104 +59,102 @@ static struct irqaction g2_dma_irq = {
        .flags          = SA_INTERRUPT,
 };
 
-static int g2_enable_dma(struct dma_info *info)
+static int g2_enable_dma(struct dma_channel *chan)
 {
-       unsigned int chan = info->chan;
+       unsigned int chan_nr = chan->chan;
 
-       g2_dma->channel[chan].chan_enable = 1;
-       g2_dma->channel[chan].xfer_enable = 1;
+       g2_dma->channel[chan_nr].chan_enable = 1;
+       g2_dma->channel[chan_nr].xfer_enable = 1;
 
        return 0;
 }
 
-static int g2_disable_dma(struct dma_info *info)
+static int g2_disable_dma(struct dma_channel *chan)
 {
-       unsigned int chan = info->chan;
+       unsigned int chan_nr = chan->chan;
 
-       g2_dma->channel[chan].chan_enable = 0;
-       g2_dma->channel[chan].xfer_enable = 0;
+       g2_dma->channel[chan_nr].chan_enable = 0;
+       g2_dma->channel[chan_nr].xfer_enable = 0;
 
        return 0;
 }
 
-static int g2_xfer_dma(struct dma_info *info)
+static int g2_xfer_dma(struct dma_channel *chan)
 {
-       unsigned int chan = info->chan;
+       unsigned int chan_nr = chan->chan;
 
-       if (info->sar & 31) {
-               printk("g2dma: unaligned source 0x%lx\n", info->sar);
+       if (chan->sar & 31) {
+               printk("g2dma: unaligned source 0x%lx\n", chan->sar);
                return -EINVAL;
        }
 
-       if (info->dar & 31) {
-               printk("g2dma: unaligned dest 0x%lx\n", info->dar);
+       if (chan->dar & 31) {
+               printk("g2dma: unaligned dest 0x%lx\n", chan->dar);
                return -EINVAL;
        }
 
        /* Align the count */
-       if (info->count & 31)
-               info->count = (info->count + (32 - 1)) & ~(32 - 1);
+       if (chan->count & 31)
+               chan->count = (chan->count + (32 - 1)) & ~(32 - 1);
 
        /* Fixup destination */
-       info->dar += 0xa0800000;
+       chan->dar += 0xa0800000;
 
        /* Fixup direction */
-       info->mode = !info->mode;
+       chan->mode = !chan->mode;
 
-       flush_icache_range((unsigned long)info->sar, info->count);
+       flush_icache_range((unsigned long)chan->sar, chan->count);
 
-       g2_disable_dma(info);
+       g2_disable_dma(chan);
 
-       g2_dma->channel[chan].g2_addr   = info->dar & 0x1fffffe0;
-       g2_dma->channel[chan].root_addr = info->sar & 0x1fffffe0;
-       g2_dma->channel[chan].size      = (info->count & ~31) | 0x80000000;
-       g2_dma->channel[chan].direction = info->mode;
+       g2_dma->channel[chan_nr].g2_addr   = chan->dar & 0x1fffffe0;
+       g2_dma->channel[chan_nr].root_addr = chan->sar & 0x1fffffe0;
+       g2_dma->channel[chan_nr].size      = (chan->count & ~31) | 0x80000000;
+       g2_dma->channel[chan_nr].direction = chan->mode;
 
        /*
         * bit 0 - ???
         * bit 1 - if set, generate a hardware event on transfer completion
         * bit 2 - ??? something to do with suspend?
         */
-       g2_dma->channel[chan].ctrl      = 5; /* ?? */
+       g2_dma->channel[chan_nr].ctrl   = 5; /* ?? */
+
+       g2_enable_dma(chan);
 
-       g2_enable_dma(info);
-       
        /* debug cruft */
        pr_debug("count, sar, dar, mode, ctrl, chan, xfer: %ld, 0x%08lx, "
                 "0x%08lx, %ld, %ld, %ld, %ld\n",
-                g2_dma->channel[chan].size,
-                g2_dma->channel[chan].root_addr,
-                g2_dma->channel[chan].g2_addr,
-                g2_dma->channel[chan].direction,
-                g2_dma->channel[chan].ctrl,
-                g2_dma->channel[chan].chan_enable,
-                g2_dma->channel[chan].xfer_enable);
+                g2_dma->channel[chan_nr].size,
+                g2_dma->channel[chan_nr].root_addr,
+                g2_dma->channel[chan_nr].g2_addr,
+                g2_dma->channel[chan_nr].direction,
+                g2_dma->channel[chan_nr].ctrl,
+                g2_dma->channel[chan_nr].chan_enable,
+                g2_dma->channel[chan_nr].xfer_enable);
 
        return 0;
 }
 
 static struct dma_ops g2_dma_ops = {
-       .name           = "G2 DMA",
        .xfer           = g2_xfer_dma,
 };
 
+static struct dma_info g2_dma_info = {
+       .name           = "G2 DMA",
+       .nr_channels    = 4,
+       .ops            = &g2_dma_ops,
+       .flags          = DMAC_CHANNELS_TEI_CAPABLE,
+};
+
 static int __init g2_dma_init(void)
 {
-       int i, base;
-
        setup_irq(HW_EVENT_G2_DMA, &g2_dma_irq);
 
        /* Magic */
        g2_dma->wait_state      = 27;
        g2_dma->magic           = 0x4659404f;
 
-       /* G2 channels come after on-chip and pvr2 */
-       base = ONCHIP_NR_DMA_CHANNELS + PVR2_NR_DMA_CHANNELS;
-
-       for (i = 0; i < G2_NR_DMA_CHANNELS; i++)
-               dma_info[base + i].ops = &g2_dma_ops;
-       
-       return register_dmac(&g2_dma_ops);
+       return register_dmac(&g2_dma_info);
 }
 
 static void __exit g2_dma_exit(void)
index ee54ada..2e1d58f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * NEC PowerVR 2 (Dreamcast) DMA support
  *
- * Copyright (C) 2003  Paul Mundt
+ * 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
@@ -38,7 +38,7 @@ static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id, struct pt_regs *reg
        return IRQ_HANDLED;
 }
 
-static int pvr2_request_dma(struct dma_info *info)
+static int pvr2_request_dma(struct dma_channel *chan)
 {
        if (ctrl_inl(PVR2_DMA_MODE) != 0)
                return -EBUSY;
@@ -48,21 +48,21 @@ static int pvr2_request_dma(struct dma_info *info)
        return 0;
 }
 
-static int pvr2_get_dma_residue(struct dma_info *info)
+static int pvr2_get_dma_residue(struct dma_channel *chan)
 {
        return xfer_complete == 0;
 }
 
-static int pvr2_xfer_dma(struct dma_info *info)
+static int pvr2_xfer_dma(struct dma_channel *chan)
 {
-       if (info->sar || !info->dar)
+       if (chan->sar || !chan->dar)
                return -EINVAL;
 
        xfer_complete = 0;
 
-       ctrl_outl(info->dar, PVR2_DMA_ADDR);
-       ctrl_outl(info->count, PVR2_DMA_COUNT);
-       ctrl_outl(info->mode & DMA_MODE_MASK, PVR2_DMA_MODE);
+       ctrl_outl(chan->dar, PVR2_DMA_ADDR);
+       ctrl_outl(chan->count, PVR2_DMA_COUNT);
+       ctrl_outl(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE);
 
        return 0;
 }
@@ -74,26 +74,24 @@ static struct irqaction pvr2_dma_irq = {
 };
 
 static struct dma_ops pvr2_dma_ops = {
-       .name           = "PowerVR 2 DMA",
        .request        = pvr2_request_dma,
        .get_residue    = pvr2_get_dma_residue,
        .xfer           = pvr2_xfer_dma,
 };
 
+static struct dma_info pvr2_dma_info = {
+       .name           = "PowerVR 2 DMA",
+       .nr_channels    = 1,
+       .ops            = &pvr2_dma_ops,
+       .flags          = DMAC_CHANNELS_TEI_CAPABLE,
+};
+
 static int __init pvr2_dma_init(void)
 {
-       int i, base;
-
        setup_irq(HW_EVENT_PVR2_DMA, &pvr2_dma_irq);
        request_dma(PVR2_CASCADE_CHAN, "pvr2 cascade");
 
-       /* PVR2 cascade comes after on-chip DMAC */
-       base = ONCHIP_NR_DMA_CHANNELS;
-
-       for (i = 0; i < PVR2_NR_DMA_CHANNELS; i++)
-               dma_info[base + i].ops = &pvr2_dma_ops;
-
-       return register_dmac(&pvr2_dma_ops);
+       return register_dmac(&pvr2_dma_info);
 }
 
 static void __exit pvr2_dma_exit(void)
index ff61697..83de7ef 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
 static int gapspci_dma_used = 0;
 
-void *__pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-                          dma_addr_t * dma_handle)
+void *dreamcast_consistent_alloc(struct device *dev, size_t size,
+                                dma_addr_t *dma_handle, int flag)
 {
        unsigned long buf;
 
-       if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE)
+       if (dev && dev->bus != &pci_bus_type)
                return NULL;
 
-       buf = GAPSPCI_DMA_BASE+gapspci_dma_used;
+       if (gapspci_dma_used + size > GAPSPCI_DMA_SIZE)
+               return ERR_PTR(-EINVAL);
+
+       buf = GAPSPCI_DMA_BASE + gapspci_dma_used;
 
        gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
-       
+
        *dma_handle = (dma_addr_t)buf;
 
        buf = P2SEGADDR(buf);
@@ -52,10 +57,15 @@ void *__pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
        return (void *)buf;
 }
 
-void __pci_free_consistent(struct pci_dev *hwdev, size_t size,
+int dreamcast_consistent_free(struct device *dev, size_t size,
                         void *vaddr, dma_addr_t dma_handle)
 {
+       if (dev && dev->bus != &pci_bus_type)
+               return -EINVAL;
+
        /* XXX */
        gapspci_dma_used = 0;
+
+       return 0;
 }
 
index d07572b..cf30e2f 100644 (file)
@@ -62,7 +62,7 @@ void __init pcibios_fixup_irqs(void)
 {
        struct pci_dev *dev = 0;
 
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                /*
                 * The interrupt routing semantics here are quite trivial.
                 *
index 7b5dbe1..0c590fc 100644 (file)
 
 int pci_fixup_pcic(void)
 {
-       unsigned long mcr;
+       unsigned long bcr1, mcr;
 
-       outl(0xfb900047, SH7751_PCICONF1);
-       outl(0xab000001, SH7751_PCICONF4);
+       bcr1 = inl(SH7751_BCR1);
+       bcr1 |= 0x40080000;     /* Enable Bit 19 BREQEN, set PCIC to slave */
+       outl(bcr1, PCI_REG(SH7751_PCIBCR1));
+
+       /* Enable all interrupts, so we known what to fix */
+       outl(0x0000c3ff, PCI_REG(SH7751_PCIINTM));
+       outl(0x0000380f, PCI_REG(SH7751_PCIAINTM));
+
+       outl(0xfb900047, PCI_REG(SH7751_PCICONF1));
+       outl(0xab000001, PCI_REG(SH7751_PCICONF4));
 
        mcr = inl(SH7751_MCR);
        mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
-       outl(mcr, SH7751_PCIMCR);
+       outl(mcr, PCI_REG(SH7751_PCIMCR));
 
+       outl(0x0c000000, PCI_REG(SH7751_PCICONF5));
+       outl(0xd0000000, PCI_REG(SH7751_PCICONF6));
+       outl(0x0c000000, PCI_REG(SH7751_PCILAR0));
+       outl(0x00000000, PCI_REG(SH7751_PCILAR1));
        return 0;
 }
-
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);
+}
index 2bceb43..beafa11 100644 (file)
@@ -61,7 +61,12 @@ EXPORT_SYMBOL(board_pci_channels);
 static struct sh7751_pci_address_map sh7751_pci_map = {
        .window0        = {
                .base   = SH7751_CS3_BASE_ADDR,
-               .size   = 0x03f00000,
+               .size   = 0x04000000,
+       },
+
+       .window1        = {
+               .base   = 0x00000000,   /* Unused */
+               .size   = 0x00000000,   /* Unused */
        },
 
        .flags  = SH7751_PCIC_NO_RESET,
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 },
+};
+
index 4be02f6..2688f41 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <asm/pci.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>   /* irqreturn_t */
 
 #include "pci-st40.h"
 
 #define ST40PCI_REG_ADDRESS      (ST40PCI_BASE_ADDRESS+0x07000000)
 
 #define ST40PCI_REG(x) (ST40PCI_REG_ADDRESS+(ST40PCI_##x))
+#define ST40PCI_REG_INDEXED(reg, index)                                \
+       (ST40PCI_REG(reg##0) +                                  \
+         ((ST40PCI_REG(reg##1) - ST40PCI_REG(reg##0))*index))
 
 #define ST40PCI_WRITE(reg,val) writel((val),ST40PCI_REG(reg))
 #define ST40PCI_WRITE_SHORT(reg,val) writew((val),ST40PCI_REG(reg))
 #define ST40PCI_WRITE_BYTE(reg,val) writeb((val),ST40PCI_REG(reg))
+#define ST40PCI_WRITE_INDEXED(reg, index, val)                         \
+        writel((val), ST40PCI_REG_INDEXED(reg, index));
 
 #define ST40PCI_READ(reg) readl(ST40PCI_REG(reg))
 #define ST40PCI_READ_SHORT(reg) readw(ST40PCI_REG(reg))
 #define ST40PCI_READ_BYTE(reg) readb(ST40PCI_REG(reg))
 
-#define ST40PCI_SERR_IRQ        64
-#define ST40PCI_SERR_INT_GROUP  0
-#define ST40PCI_SERR_INT_POS    0
-#define ST40PCI_SERR_INT_PRI    15
-
-#define ST40PCI_ERR_IRQ        65
-#define ST40PCI_ERR_INT_GROUP   1
-#define ST40PCI_ERR_INT_POS     1
-#define ST40PCI_ERR_INT_PRI     14
+#define ST40PCI_SERR_IRQ       64
+#define ST40PCI_ERR_IRQ                65
 
 
 /* Macros to extract PLL params */
 #define PLL_25MHZ 0x793c8512
 #define PLL_33MHZ PLL_SET(18,88,3,295)
 
+static void pci_set_rbar_region(unsigned int region,     unsigned long localAddr,
+                        unsigned long pciOffset, unsigned long regionSize);
+
+/*
+ * The pcibios_map_platform_irq function is defined in the appropriate
+ * board specific code and referenced here
+ */
+extern int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
 
 static __init void SetPCIPLL(void)
 {
-       /* Stop the PLL */
-       writel(0, PLLPCICR);
+       {
+               /* Lets play with the PLL values */
+               unsigned long pll1cr1;
+               unsigned long mdiv, ndiv, pdiv;
+               unsigned long muxcr;
+               unsigned int muxcr_ratios[4] = { 8, 16, 21, 1 };
+               unsigned int freq;
+
+#define CLKGENA            0xbb040000
+#define CLKGENA_PLL2_MUXCR CLKGENA + 0x48
+               pll1cr1 = ctrl_inl(PLLPCICR);
+               printk("PLL1CR1 %08lx\n", pll1cr1);
+               mdiv = PLL_MDIV(pll1cr1);
+               ndiv = PLL_NDIV(pll1cr1);
+               pdiv = PLL_PDIV(pll1cr1);
+               printk("mdiv %02lx ndiv %02lx pdiv %02lx\n", mdiv, ndiv, pdiv);
+               freq = ((2*27*ndiv)/mdiv) / (1 << pdiv);
+               printk("PLL freq %dMHz\n", freq);
+               muxcr = ctrl_inl(CLKGENA_PLL2_MUXCR);
+               printk("PCI freq %dMhz\n", freq / muxcr_ratios[muxcr & 3]);
+       }
+}
 
-       /* Always run at 33Mhz. The PCI clock is totally async 
-        * to the rest of the system
-        */
-       writel(PLL_33MHZ | PLLPCICR_POWERON, PLLPCICR);
 
-       printk("ST40PCI: Waiting for PCI PLL to lock\n");
-       while ((readl(PLLPCICR) & PLLPCICR_LOCK) == 0);
-       writel(readl(PLLPCICR) | PLLPCICR_OUT_EN, PLLPCICR);
+struct pci_err {
+  unsigned mask;
+  const char *error_string;
+};
+
+static struct pci_err int_error[]={
+  { INT_MNLTDIM,"MNLTDIM: Master non-lock transfer"},
+  { INT_TTADI,  "TTADI: Illegal byte enable in I/O transfer"},
+  { INT_TMTO,   "TMTO: Target memory read/write timeout"},
+  { INT_MDEI,   "MDEI: Master function disable error"},
+  { INT_APEDI,  "APEDI: Address parity error"},
+  { INT_SDI,    "SDI: SERR detected"},
+  { INT_DPEITW, "DPEITW: Data parity error target write"},
+  { INT_PEDITR, "PEDITR: PERR detected"},
+  { INT_TADIM,  "TADIM: Target abort detected"},
+  { INT_MADIM,  "MADIM: Master abort detected"},
+  { INT_MWPDI,  "MWPDI: PERR from target at data write"},
+  { INT_MRDPEI, "MRDPEI: Master read data parity error"}
+};
+#define NUM_PCI_INT_ERRS (sizeof(int_error)/sizeof(struct pci_err))
+
+static struct pci_err aint_error[]={
+  { AINT_MBI,   "MBI: Master broken"},
+  { AINT_TBTOI, "TBTOI: Target bus timeout"},
+  { AINT_MBTOI, "MBTOI: Master bus timeout"},
+  { AINT_TAI,   "TAI: Target abort"},
+  { AINT_MAI,   "MAI: Master abort"},
+  { AINT_RDPEI, "RDPEI: Read data parity"},
+  { AINT_WDPE,  "WDPE: Write data parity"}
+};
+
+#define NUM_PCI_AINT_ERRS (sizeof(aint_error)/sizeof(struct pci_err))
+
+static void print_pci_errors(unsigned reg,struct pci_err *error,int num_errors)
+{
+  int i;
+
+  for(i=0;i<num_errors;i++) {
+    if(reg & error[i].mask) {
+      printk("%s\n",error[i].error_string);
+    }
+  }
+
 }
 
 
+static char * pci_commands[16]={
+       "Int Ack",
+       "Special Cycle",
+       "I/O Read",
+       "I/O Write",
+       "Reserved",
+       "Reserved",
+       "Memory Read",
+       "Memory Write",
+       "Reserved",
+       "Reserved",
+       "Configuration Read",
+       "Configuration Write",
+       "Memory Read Multiple",
+       "Dual Address Cycle",
+       "Memory Read Line",
+       "Memory Write-and-Invalidate"
+};
+
 static irqreturn_t st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs)
 {
-
        unsigned pci_int, pci_air, pci_cir, pci_aint;
+       static int count=0;
+
+
+       pci_int = ST40PCI_READ(INT);pci_aint = ST40PCI_READ(AINT);
+       pci_cir = ST40PCI_READ(CIR);pci_air = ST40PCI_READ(AIR);
+
+       /* Reset state to stop multiple interrupts */
+        ST40PCI_WRITE(INT, ~0); ST40PCI_WRITE(AINT, ~0);
+
+
+       if(++count>1) return IRQ_HANDLED;
+
+       printk("** PCI ERROR **\n");
 
-       pci_int = ST40PCI_READ(INT);
-       pci_cir = ST40PCI_READ(CIR);
-       pci_air = ST40PCI_READ(AIR);
+        if(pci_int) {
+               printk("** INT register status\n");
+               print_pci_errors(pci_int,int_error,NUM_PCI_INT_ERRS);
+       }
 
-       if (pci_int) {
-               printk("PCI INTERRUPT!\n");
-               printk("PCI INT -> 0x%x\n", pci_int & 0xffff);
-               printk("PCI AIR -> 0x%x\n", pci_air);
-               printk("PCI CIR -> 0x%x\n", pci_cir);
-               ST40PCI_WRITE(INT, ~0);
+        if(pci_aint) {
+               printk("** AINT register status\n");
+               print_pci_errors(pci_aint,aint_error,NUM_PCI_AINT_ERRS);
        }
 
-       pci_aint = ST40PCI_READ(AINT);
-       if (pci_aint) {
-               printk("PCI ARB INTERRUPT!\n");
-               printk("PCI AINT -> 0x%x\n", pci_aint);
-               printk("PCI AIR -> 0x%x\n", pci_air);
-               printk("PCI CIR -> 0x%x\n", pci_cir);
-               ST40PCI_WRITE(AINT, ~0);
+       printk("** Address and command info\n");
+
+       printk("** Command  %s : Address 0x%x\n",
+              pci_commands[pci_cir&0xf],pci_air);
+
+       if(pci_cir&CIR_PIOTEM) {
+               printk("CIR_PIOTEM:PIO transfer error for master\n");
+       }
+        if(pci_cir&CIR_RWTET) {
+               printk("CIR_RWTET:Read/Write transfer error for target\n");
        }
 
        return IRQ_HANDLED;
@@ -119,7 +214,7 @@ static irqreturn_t st40_pci_irq(int irq, void *dev_instance, struct pt_regs *reg
 /* Rounds a number UP to the nearest power of two. Used for
  * sizing the PCI window.
  */
-static u32 __init r2p2(u32 num)
+static u32 r2p2(u32 num)
 {
        int i = 31;
        u32 tmp = num;
@@ -179,12 +274,16 @@ int __init st40pci_init(unsigned memStart, unsigned memSize)
        /* Loop while core resets */
        while (ST40PCI_READ(CR) & CR_SOFT_RESET);
 
+       /* Switch off interrupts */
+       ST40PCI_WRITE(INTM, 0);
+       ST40PCI_WRITE(AINT, 0);
+
        /* Now, lets reset all the cards on the bus with extreme prejudice */
        ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_RSTCTL);
        udelay(250);
 
        /* Set bus active, take it out of reset */
-       ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_CFINT | CR_PFCS | CR_PFE);
+       ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_BMAM | CR_CFINT | CR_PFCS | CR_PFE);
 
        /* The PCI spec says that no access must be made to the bus until 1 second
         * after reset. This seem ludicrously long, but some delay is needed here
@@ -219,37 +318,20 @@ int __init st40pci_init(unsigned memStart, unsigned memSize)
        /* Set up the 64K window */
        ST40PCI_WRITE(IOBMR, 0x0);
 
-       /* Now we set up the mbars so the PCI bus can see the memory of the machine */
+       /* Now we set up the mbars so the PCI bus can see the local memory */
+       /* Expose a 256M window starting at PCI address 0... */
+       ST40PCI_WRITE(CSR_MBAR0, 0);
+       ST40PCI_WRITE(LSR0, 0x0fff0001);
 
-       if (memSize < (64 * 1024)) {
-               printk("Ridiculous memory size of 0x%x?\n",memSize);
-               return 0;
-       }
-
-       lsr0 =
-           (memSize >
-            (512 * 1024 * 1024)) ? 0x1fff0001 : ((r2p2(memSize) -
-                                                  0x10000) | 0x1);
-
-       ST40PCI_WRITE(LSR0, lsr0);
-
-       ST40PCI_WRITE(CSR_MBAR0, memStart);
-       ST40PCI_WRITE(LAR0, memStart);
+       /* ... and set up the initial incomming window to expose all of RAM */
+       pci_set_rbar_region(7, memStart, memStart, memSize);
 
        /* Maximise timeout values */
        ST40PCI_WRITE_BYTE(CSR_TRDY, 0xff);
        ST40PCI_WRITE_BYTE(CSR_RETRY, 0xff);
        ST40PCI_WRITE_BYTE(CSR_MIT, 0xff);
 
-
-       /* Install the pci interrupt handlers */
-       make_intc2_irq(ST40PCI_SERR_IRQ, INTC2_BASE0,
-                      ST40PCI_SERR_INT_GROUP, ST40PCI_SERR_INT_POS,
-                      ST40PCI_SERR_INT_PRI);
-
-       make_intc2_irq(ST40PCI_ERR_IRQ, INTC2_BASE0, ST40PCI_ERR_INT_GROUP,
-                      ST40PCI_ERR_INT_POS, ST40PCI_ERR_INT_PRI);
-
+       ST40PCI_WRITE_BYTE(PERF,PERF_MASTER_WRITE_POSTING);
 
        return 1;
 }
@@ -332,7 +414,7 @@ static int st40pci_write(struct pci_bus *bus, unsigned int devfn, int where, int
        return PCIBIOS_SUCCESSFUL;
 }
 
-static struct pci_ops pci_config_ops = {
+struct pci_ops st40pci_config_ops = {
        .read =         st40pci_read,
        .write =        st40pci_write,
 };
@@ -348,36 +430,12 @@ static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
 }
 
 
-/* This needs to be shunted out of here into the board specific bit */
-#define HARP_PCI_IRQ    1
-#define HARP_BRIDGE_IRQ 2
-#define OVERDRIVE_SLOT0_IRQ 0
-
-static int __init map_harp_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
-       switch (slot) {
-#ifdef CONFIG_SH_STB1_HARP
-       case 2:         /*This is the PCI slot on the */
-               return HARP_PCI_IRQ;
-       case 1:         /* this is the bridge */
-               return HARP_BRIDGE_IRQ;
-#elif defined(CONFIG_SH_STB1_OVERDRIVE)
-       case 1:
-       case 2:
-       case 3:
-               return slot - 1;
-#else
-#error Unknown board
-#endif
-       default:
-               return -1;
-       }
-}
-
-void __init pcibios_init(void)
+static int __init pcibios_init(void)
 {
        extern unsigned long memory_start, memory_end;
 
+       printk(KERN_ALERT "pci-st40.c: pcibios_init\n");
+
        if (sh_mv.mv_init_pci != NULL) {
                sh_mv.mv_init_pci();
        }
@@ -392,7 +450,7 @@ void __init pcibios_init(void)
        if (request_irq(ST40PCI_ERR_IRQ, st40_pci_irq, 
                         SA_INTERRUPT, "st40pci", NULL)) {
                printk(KERN_ERR "st40pci: Cannot hook interrupt\n");
-               return;
+               return -EIO;
        }
 
        /* Enable the PCI interrupts on the device */
@@ -406,12 +464,46 @@ void __init pcibios_init(void)
 #endif
 
        /* ok, do the scan man */
-       pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
+       pci_root_bus = pci_scan_bus(0, &st40pci_config_ops, NULL);
        pci_assign_unassigned_resources();
-       pci_fixup_irqs(no_swizzle, map_harp_irq);
+       pci_fixup_irqs(no_swizzle, pcibios_map_platform_irq);
 
+       return 0;
 }
 
+subsys_initcall(pcibios_init);
+
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
 }
+
+/*
+ * Publish a region of local address space over the PCI bus
+ * to other devices.
+ */
+static void pci_set_rbar_region(unsigned int region,     unsigned long localAddr,
+                        unsigned long pciOffset, unsigned long regionSize)
+{
+       unsigned long mask;
+
+       if (region > 7)
+               return;
+
+       if (regionSize > (512 * 1024 * 1024))
+               return;
+
+       mask = r2p2(regionSize) - 0x10000;
+
+       /* Diable the region (in case currently in use, should never happen) */
+       ST40PCI_WRITE_INDEXED(RSR, region, 0);
+
+       /* Start of local address space to publish */
+       ST40PCI_WRITE_INDEXED(RLAR, region, PHYSADDR(localAddr) );
+
+       /* Start of region in PCI address space as an offset from MBAR0 */
+       ST40PCI_WRITE_INDEXED(RBAR, region, pciOffset);
+
+       /* Size of region */
+       ST40PCI_WRITE_INDEXED(RSR, region, mask | 1);
+}
+
index 2e3451a..d729e0c 100644 (file)
 #define ST40PCI_LAR0          0x1c
 
 #define ST40PCI_INT           0x24
+#define INT_MNLTDIM           (1<<15)
+#define INT_TTADI             (1<<14)
+#define INT_TMTO              (1<<9)
+#define INT_MDEI              (1<<8)
+#define INT_APEDI             (1<<7)
+#define INT_SDI               (1<<6)
+#define INT_DPEITW            (1<<5)
+#define INT_PEDITR            (1<<4)
+#define INT_TADIM             (1<<3)
 #define INT_MADIM             (1<<2)
+#define INT_MWPDI             (1<<1)
+#define INT_MRDPEI            (1<<0)
 
 
 #define ST40PCI_INTM          0x28
 #define ST40PCI_AIR           0x2c
+
 #define ST40PCI_CIR           0x30
+#define CIR_PIOTEM            (1<<31)
+#define CIR_RWTET             (1<<26)
+
 #define ST40PCI_AINT          0x40
+#define AINT_MBI              (1<<13)
+#define AINT_TBTOI            (1<<12)
+#define AINT_MBTOI            (1<<11)
+#define AINT_TAI              (1<<3)
+#define AINT_MAI              (1<<2)
+#define AINT_RDPEI            (1<<1)
+#define AINT_WDPE             (1<<0)
+
 #define ST40PCI_AINTM         0x44
 #define ST40PCI_BMIR          0x48
 #define ST40PCI_PAR           0x4c
 #define ST40PCI_IOBMR         0x74
 #define ST40PCI_PDR           0x78
 
+/* H8 specific registers start here */
+#define ST40PCI_WCBAR         0x7c
+#define ST40PCI_LOCCFG_UNLOCK 0x34
+
+#define ST40PCI_RBAR0         0x100
+#define ST40PCI_RSR0          0x104
+#define ST40PCI_RLAR0         0x108
+
+#define ST40PCI_RBAR1         0x110
+#define ST40PCI_RSR1          0x114
+#define ST40PCI_RLAR1         0x118
+
+
+#define ST40PCI_RBAR2         0x120
+#define ST40PCI_RSR2          0x124
+#define ST40PCI_RLAR2         0x128
+
+#define ST40PCI_RBAR3         0x130
+#define ST40PCI_RSR3          0x134
+#define ST40PCI_RLAR3         0x138
+
+#define ST40PCI_RBAR4         0x140
+#define ST40PCI_RSR4          0x144
+#define ST40PCI_RLAR4         0x148
+
+#define ST40PCI_RBAR5         0x150
+#define ST40PCI_RSR5          0x154
+#define ST40PCI_RLAR5         0x158
+
+#define ST40PCI_RBAR6         0x160
+#define ST40PCI_RSR6          0x164
+#define ST40PCI_RLAR6         0x168
+
+#define ST40PCI_RBAR7         0x170
+#define ST40PCI_RSR7          0x174
+#define ST40PCI_RLAR7         0x178
+
+
+#define ST40PCI_RBAR(n)      (0x100+(0x10*(n)))
+#define ST40PCI_RSR(n)       (0x104+(0x10*(n)))
+#define ST40PCI_RLAR(n)      (0x108+(0x10*(n)))
+
+#define ST40PCI_PERF               0x80
+#define PERF_MASTER_WRITE_POSTING  (1<<4)
+/* H8 specific registers end here */
+
+
 /* These are configs space registers */
 #define ST40PCI_CSR_VID               0x10000
 #define ST40PCI_CSR_DID               0x10002
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;
+}
index be2c823..f76901e 100644 (file)
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 
 #include <linux/spinlock.h>
 #include <linux/cache.h>
index eb38f91..389353f 100644 (file)
@@ -2,3 +2,5 @@
 # Makefile for the Linux/SuperH SH-2 backends.
 #
 
+obj-y  := probe.o
+
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;
+}
+
index 196c5f0..a64532e 100644 (file)
@@ -2,5 +2,5 @@
 # Makefile for the Linux/SuperH SH-3 backends.
 #
 
-obj-y  := ex.o
+obj-y  := ex.o probe.o
 
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;
+}
+
index fd59761..ead1071 100644 (file)
@@ -2,8 +2,9 @@
 # Makefile for the Linux/SuperH SH-4 backends.
 #
 
-obj-y  := fpu.o ex.o
+obj-y  := ex.o probe.o
 
+obj-$(CONFIG_SH_FPU)                    += fpu.o
 obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)     += irq_intc2.o
 obj-$(CONFIG_SH_STORE_QUEUES)          += sq.o
 
index 2cc32ad..8221e9d 100644 (file)
@@ -37,8 +37,11 @@ ENTRY(exception_handling_table)
        .long   exception_error ! address error load
        .long   exception_error ! address error store   /* 100 */
 #endif
-
+#if defined(CONFIG_SH_FPU)
        .long   do_fpu_error            /* 120 */
+#else
+       .long   exception_error         /* 120 */
+#endif
        .long   exception_error         /* 140 */
        .long   system_call     ! Unconditional Trap     /* 160 */
        .long   exception_error ! reserved_instruction (filled by trap_init) /* 180 */
@@ -126,8 +129,13 @@ ENTRY(interrupt_table)
        .long   exception_error                 ! 46
        .long   exception_error                 ! 47
 #endif
+#if defined(CONFIG_SH_FPU)
        .long   do_fpu_state_restore    ! 48    /* 800 */
        .long   do_fpu_state_restore    ! 49    /* 820 */
+#else
+       .long   exception_error
+       .long   exception_error
+#endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7751)
        .long   exception_error                 /* 840 */
        .long   exception_error
@@ -217,6 +225,66 @@ ENTRY(interrupt_table)
        .long   exception_error
        .long   do_IRQ  ! ADC   adi
        .long   do_IRQ  ! CMT   cmti    /* FA0 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
+       .long   do_IRQ  !  50 0x840
+       .long   do_IRQ  !  51 0x860
+       .long   do_IRQ  !  52 0x880
+       .long   do_IRQ  !  53 0x8a0
+       .long   do_IRQ  !  54 0x8c0
+       .long   do_IRQ  !  55 0x8e0
+       .long   do_IRQ  !  56 0x900
+       .long   do_IRQ  !  57 0x920
+       .long   do_IRQ  !  58 0x940
+       .long   do_IRQ  !  59 0x960
+       .long   do_IRQ  !  60 0x980
+       .long   do_IRQ  !  61 0x9a0
+       .long   do_IRQ  !  62 0x9c0
+       .long   do_IRQ  !  63 0x9e0
+       .long   do_IRQ  !  64 0xa00
+       .long   do_IRQ  !  65 0xa20
+       .long   do_IRQ  !  66 0xa40
+       .long   do_IRQ  !  67 0xa60
+       .long   do_IRQ  !  68 0xa80
+       .long   do_IRQ  !  69 0xaa0
+       .long   do_IRQ  !  70 0xac0
+       .long   do_IRQ  !  71 0xae0
+       .long   do_IRQ  !  72 0xb00
+       .long   do_IRQ  !  73 0xb20
+       .long   do_IRQ  !  74 0xb40
+       .long   do_IRQ  !  75 0xb60
+       .long   do_IRQ  !  76 0xb80
+       .long   do_IRQ  !  77 0xba0
+       .long   do_IRQ  !  78 0xbc0
+       .long   do_IRQ  !  79 0xbe0
+       .long   do_IRQ  !  80 0xc00
+       .long   do_IRQ  !  81 0xc20
+       .long   do_IRQ  !  82 0xc40
+       .long   do_IRQ  !  83 0xc60
+       .long   do_IRQ  !  84 0xc80
+       .long   do_IRQ  !  85 0xca0
+       .long   do_IRQ  !  86 0xcc0
+       .long   do_IRQ  !  87 0xce0
+       .long   do_IRQ  !  88 0xd00
+       .long   do_IRQ  !  89 0xd20
+       .long   do_IRQ  !  90 0xd40
+       .long   do_IRQ  !  91 0xd60
+       .long   do_IRQ  !  92 0xd80
+       .long   do_IRQ  !  93 0xda0
+       .long   do_IRQ  !  94 0xdc0
+       .long   do_IRQ  !  95 0xde0
+       .long   do_IRQ  !  96 0xe00
+       .long   do_IRQ  !  97 0xe20
+       .long   do_IRQ  !  98 0xe40
+       .long   do_IRQ  !  99 0xe60
+       .long   do_IRQ  ! 100 0xe80
+       .long   do_IRQ  ! 101 0xea0
+       .long   do_IRQ  ! 102 0xec0
+       .long   do_IRQ  ! 103 0xee0
+       .long   do_IRQ  ! 104 0xf00
+       .long   do_IRQ  ! 105 0xf20
+       .long   do_IRQ  ! 106 0xf40
+       .long   do_IRQ  ! 107 0xf60
+       .long   do_IRQ  ! 108 0xf80
 #elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
        .long   exception_error                 !  50 0x840
        .long   exception_error                 !  51 0x860
index ec99f4c..099ebbf 100644 (file)
 
 
 struct intc2_data {
-       unsigned int addr;      /* Address of Interrupt Priority Register */
-       int mask; /*Mask to apply */
+       unsigned char msk_offset;
+       unsigned char msk_shift;
+#ifdef CONFIG_CPU_SUBTYPE_ST40
+       int (*clear_irq) (int);
+#endif
 };
 
 
@@ -56,33 +59,34 @@ static struct hw_interrupt_type intc2_irq_type = {
 
 static void disable_intc2_irq(unsigned int irq)
 {
-       unsigned addr;
-       int offset=irq-INTC2_FIRST_IRQ;
-       unsigned val,flags;
+       int irq_offset = irq - INTC2_FIRST_IRQ;
+       int msk_shift, msk_offset;
 
        // Sanity check
-       if(offset<0 || offset>=NR_INTC2_IRQS) return;
-
-       addr=intc2_data[offset].addr+INTC2_INTMSK_OFFSET;
+       if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
+               return;
 
-       local_irq_save(flags);
-       val=ctrl_inl(addr);
-       val|=intc2_data[offset].mask;
-       ctrl_outl(val,addr);
+       msk_shift = intc2_data[irq_offset].msk_shift;
+       msk_offset = intc2_data[irq_offset].msk_offset;
 
-       local_irq_restore(flags);
+       ctrl_outl(1<<msk_shift,
+                 INTC2_BASE+INTC2_INTMSK_OFFSET+msk_offset);
 }
 
 static void enable_intc2_irq(unsigned int irq)
 {
-       int offset=irq-INTC2_FIRST_IRQ;
+       int irq_offset = irq - INTC2_FIRST_IRQ;
+       int msk_shift, msk_offset;
 
-       // Sanity check
-       if(offset<0 || offset>=NR_INTC2_IRQS) return;
+       /* Sanity check */
+       if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
+               return;
 
-       ctrl_outl(intc2_data[offset].mask,
-                 intc2_data[offset].addr+INTC2_INTMSKCLR_OFFSET);
+       msk_shift = intc2_data[irq_offset].msk_shift;
+       msk_offset = intc2_data[irq_offset].msk_offset;
 
+       ctrl_outl(1<<msk_shift,
+                 INTC2_BASE+INTC2_INTMSKCLR_OFFSET+msk_offset);
 }
 
 static void mask_and_ack_intc2(unsigned int irq)
@@ -94,28 +98,52 @@ static void end_intc2_irq(unsigned int irq)
 {
        if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
                enable_intc2_irq(irq);
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40
+       if (intc2_data[irq - INTC2_FIRST_IRQ].clear_irq)
+               intc2_data[irq - INTC2_FIRST_IRQ].clear_irq (irq);
+#endif
 }
 
-void make_intc2_irq(unsigned int irq, unsigned int addr, 
-                   unsigned int group,int pos, int priority)
+/*
+ * Setup an INTC2 style interrupt.
+ * NOTE: Unlike IPR interrupts, parameters are not shifted by this code,
+ * allowing the use of the numbers straight out of the datasheet.
+ * For example:
+ *    PIO1 which is INTPRI00[19,16] and INTMSK00[13]
+ * would be:               ^     ^             ^  ^
+ *                         |     |             |  |
+ *    make_intc2_irq(84,   0,   16,            0, 13);
+ */
+void make_intc2_irq(unsigned int irq,
+                   unsigned int ipr_offset, unsigned int ipr_shift,
+                   unsigned int msk_offset, unsigned int msk_shift,
+                   unsigned int priority)
 {
-       int offset=irq-INTC2_FIRST_IRQ;
-       unsigned flags,val;
+       int irq_offset = irq - INTC2_FIRST_IRQ;
+       unsigned int flags;
+       unsigned long ipr;
 
-       if(offset<0 || offset>=NR_INTC2_IRQS) {
+       if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
                return;
-       }
 
        disable_irq_nosync(irq);
+
        /* Fill the data we need */
-       intc2_data[offset].addr=addr;
-       intc2_data[offset].mask=1<<pos;
+       intc2_data[irq_offset].msk_offset = msk_offset;
+       intc2_data[irq_offset].msk_shift  = msk_shift;
+#ifdef CONFIG_CPU_SUBTYPE_ST40
+       intc2_data[irq_offset].clear_irq = NULL;
+#endif
                
        /* Set the priority level */
        local_irq_save(flags);
-       val=ctrl_inl(addr+INTC2_INTPRI_OFFSET);
-       val|=(priority)<< (group<<4);
-       ctrl_outl(val,addr+INTC2_INTPRI_OFFSET);
+
+       ipr=ctrl_inl(INTC2_BASE+INTC2_INTPRI_OFFSET+ipr_offset);
+       ipr&=~(0xf<<ipr_shift);
+       ipr|=(priority)<<ipr_shift;
+       ctrl_outl(ipr, INTC2_BASE+INTC2_INTPRI_OFFSET+ipr_offset);
+
        local_irq_restore(flags);
 
        irq_desc[irq].handler=&intc2_irq_type;
@@ -123,5 +151,72 @@ void make_intc2_irq(unsigned int irq, unsigned int addr,
        disable_intc2_irq(irq);
 }
 
+#ifdef CONFIG_CPU_SUBTYPE_ST40
 
+struct intc2_init {
+       unsigned short irq;
+       unsigned char ipr_offset, ipr_shift;
+       unsigned char msk_offset, msk_shift;
+};
+
+static struct intc2_init intc2_init_data[]  __initdata = {
+       {64,  0,  0, 0,  0},    /* PCI serr */
+       {65,  0,  4, 0,  1},    /* PCI err */
+       {66,  0,  4, 0,  2},    /* PCI ad */
+       {67,  0,  4, 0,  3},    /* PCI pwd down */
+       {72,  0,  8, 0,  5},    /* DMAC INT0 */
+       {73,  0,  8, 0,  6},    /* DMAC INT1 */
+       {74,  0,  8, 0,  7},    /* DMAC INT2 */
+       {75,  0,  8, 0,  8},    /* DMAC INT3 */
+       {76,  0,  8, 0,  9},    /* DMAC INT4 */
+       {78,  0,  8, 0, 11},    /* DMAC ERR */
+       {80,  0, 12, 0, 12},    /* PIO0 */
+       {84,  0, 16, 0, 13},    /* PIO1 */
+       {88,  0, 20, 0, 14},    /* PIO2 */
+       {112, 4,  0, 4,  0},    /* Mailbox */
+#ifdef CONFIG_CPU_SUBTYPE_ST40GX1
+       {116, 4,  4, 4,  4},    /* SSC0 */
+       {120, 4,  8, 4,  8},    /* IR Blaster */
+       {124, 4, 12, 4, 12},    /* USB host */
+       {128, 4, 16, 4, 16},    /* Video processor BLITTER */
+       {132, 4, 20, 4, 20},    /* UART0 */
+       {134, 4, 20, 4, 22},    /* UART2 */
+       {136, 4, 24, 4, 24},    /* IO_PIO0 */
+       {140, 4, 28, 4, 28},    /* EMPI */
+       {144, 8,  0, 8,  0},    /* MAFE */
+       {148, 8,  4, 8,  4},    /* PWM */
+       {152, 8,  8, 8,  8},    /* SSC1 */
+       {156, 8, 12, 8, 12},    /* IO_PIO1 */
+       {160, 8, 16, 8, 16},    /* USB target */
+       {164, 8, 20, 8, 20},    /* UART1 */
+       {168, 8, 24, 8, 24},    /* Teletext */
+       {172, 8, 28, 8, 28},    /* VideoSync VTG */
+       {173, 8, 28, 8, 29},    /* VideoSync DVP0 */
+       {174, 8, 28, 8, 30},    /* VideoSync DVP1 */
+#endif
+};
+
+void __init init_IRQ_intc2(void)
+{
+       struct intc2_init *p;
+
+       printk(KERN_ALERT "init_IRQ_intc2\n");
+
+       for (p = intc2_init_data;
+            p<intc2_init_data+ARRAY_SIZE(intc2_init_data);
+            p++) {
+               make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift,
+                              p-> msk_offset, p->msk_shift, 13);
+       }
+}
+
+/* Adds a termination callback to the interrupt */
+void intc2_add_clear_irq(int irq, int (*fn)(int))
+{
+       if (irq < INTC2_FIRST_IRQ)
+               return;
+
+       intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn;
+}
 
+#endif /* CONFIG_CPU_SUBTYPE_ST40 */
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;
+}
+
index 8c2769c..1378db3 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1999, 2000  Niibe Yutaka
  *  Copyright (C) 2002  M. R. Brown
+ *  Copyright (C) 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
@@ -109,7 +110,8 @@ void scif_sercon_init(int baud)
        ctrl_outw(0, SCIF_REG);
 
        /* Set baud rate */
-       ctrl_outb((50000000 / (32 * baud)) - 1, SCIF_REG + 4);
+       ctrl_outb((CONFIG_SH_PCLK_FREQ + 16 * baud) /
+                 (32 * baud) - 1, SCIF_REG + 4);
 
        ctrl_outw(12, SCIF_REG + 24);
        ctrl_outw(8, SCIF_REG + 24);
index 9d17693..5b53e10 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: sh_bios.c,v 1.2 2003/05/04 19:29:53 lethal Exp $
- *
+/*
  *  linux/arch/sh/kernel/sh_bios.c
  *  C interface for trapping into the standard LinuxSH BIOS.
  *
index fc5ef99..a758053 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.20 2004/01/13 05:52:11 kkojima Exp $
+/* $Id: signal.c,v 1.21 2004/06/28 13:18:44 doyu Exp $
  *
  *  linux/arch/sh/kernel/signal.c
  *
@@ -155,7 +155,7 @@ struct rt_sigframe
        u16 retcode[8];
 };
 
-#ifdef CONFIG_CPU_SH4
+#ifdef CONFIG_SH_FPU
 static inline int restore_sigcontext_fpu(struct sigcontext __user *sc)
 {
        struct task_struct *tsk = current;
@@ -192,7 +192,7 @@ static inline int save_sigcontext_fpu(struct sigcontext __user *sc,
        return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
                              sizeof(long)*(16*2+2));
 }
-#endif /* CONFIG_CPU_SH4 */
+#endif /* CONFIG_SH_FPU */
 
 static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p)
@@ -213,7 +213,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p
        COPY(sr);       COPY(pc);
 #undef COPY
 
-#ifdef CONFIG_CPU_SH4
+#ifdef CONFIG_SH_FPU
        if (cpu_data->flags & CPU_HAS_FPU) {
                int owned_fp;
                struct task_struct *tsk = current;
@@ -326,7 +326,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
        COPY(sr);       COPY(pc);
 #undef COPY
 
-#ifdef CONFIG_CPU_SH4
+#ifdef CONFIG_SH_FPU
        err |= save_sigcontext_fpu(sc, regs);
 #endif
 
@@ -493,14 +493,12 @@ give_sigsegv:
 
 /*
  * OK, we're invoking a handler
- */    
+ */
 
 static void
-handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
-       struct pt_regs * regs)
+handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
+             sigset_t *oldset, struct pt_regs *regs)
 {
-       struct k_sigaction *ka = &current->sighand->action[sig-1];
-
        /* Are we from a system call? */
        if (regs->tra >= 0) {
                /* If so, check system call restarting.. */
@@ -570,6 +568,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
        siginfo_t info;
        int signr;
+       struct k_sigaction ka;
 
        /*
         * We want the common case to go fast, which
@@ -588,10 +587,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
        if (!oldset)
                oldset = &current->blocked;
 
-       signr = get_signal_to_deliver(&info, regs, NULL);
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &info, oldset, regs);
+               handle_signal(signr, &ka, &info, oldset, regs);
                return 1;
        }
 
index 3ed8e7c..b5681e3 100644 (file)
@@ -2,6 +2,12 @@
 # Makefile for SuperH-specific library files..
 #
 
-lib-y  = delay.o memcpy.o memset.o memmove.o memchr.o \
+lib-y  = delay.o memset.o memmove.o memchr.o \
         checksum.o strcasecmp.o strlen.o div64.o udivdi3.o \
         div64-generic.o
+
+memcpy-y                       := memcpy.o
+memcpy-$(CONFIG_CPU_SH4)       := memcpy-sh4.o
+
+lib-y  += $(memcpy-y)
+
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
+
index 38e004c..9489a14 100644 (file)
@@ -19,5 +19,7 @@ obj-y                 += $(mmu-y)
 ifdef CONFIG_MMU
 obj-$(CONFIG_CPU_SH3)  += tlb-sh3.o
 obj-$(CONFIG_CPU_SH4)  += tlb-sh4.o ioremap.o
+obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
 endif
 
+obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
index ee5b452..2689cb2 100644 (file)
@@ -24,7 +24,7 @@
 unsigned long __get_oc_addr(unsigned long set, unsigned long way)
 {
        unsigned long ccr;
-       
+
        /*
         * On SH-2 the way bit isn't tracked in the address field
         * if we're doing address array access .. instead, we need
@@ -48,25 +48,3 @@ unsigned long __get_oc_addr(unsigned long set, unsigned long way)
        return CACHE_OC_ADDRESS_ARRAY | (set << cpu_data->dcache.entry_shift);
 }
 
-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/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);
+}
+
index 994d928..505ede7 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: extable.c,v 1.3 2003/05/06 23:28:50 lethal Exp $
- *
+/*
  * linux/arch/sh/mm/extable.c
  *  Taken from:
  *   linux/arch/i386/mm/extable.c
index aaa8e87..9f490c2 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: ioremap.c,v 1.9 2004/02/25 04:59:10 lethal Exp $
- *
+/*
  * arch/sh/mm/ioremap.c
  *
  * Re-map IO memory to kernel address space so that we can access it.
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;
+}
+
index 2b68bb5..686738d 100644 (file)
@@ -7,7 +7,7 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
                timer_int.o )
 
 profdrvr-y                             := op_model_null.o
-profdrvr-$(CONFIG_SH_DREAMCAST)                := op_model_dreamcast.o
+profdrvr-$(CONFIG_CPU_SUBTYPE_SH7750)  := op_model_sh7750.o
 
 oprofile-y                             := $(DRIVER_OBJS) $(profdrvr-y)
 
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)
+{
+}
+
index a22d86b..99e1c68 100644 (file)
@@ -12,8 +12,9 @@ img := $(subst $(src)//,/,$(src)/$(img))
 
 quiet_cmd_ramdisk = LD      $@
 define cmd_ramdisk
-       $(LD) -T $(src)/ld.script -b binary --oformat $(O_FORMAT) -o $@ $(img)
+       $(LD) -T $(srctree)/$(src)/ld.script -b binary --oformat $(O_FORMAT) \
+               -o $@ $(img)
 endef
 
-$(obj)/ramdisk.o: $(img) $(src)/ld.script
+$(obj)/ramdisk.o: $(img) $(srctree)/$(src)/ld.script
        $(call cmd,ramdisk)
index 268bf3e..3c370a1 100644 (file)
@@ -10,7 +10,6 @@
 # Shamelessly cloned from ARM.
 #
 
-include/asm-sh/machtypes.h: $(obj)/machgen.sh $(obj)/mach-types
+include/asm-sh/machtypes.h: $(src)/gen-mach-types $(src)/mach-types
        @echo '  Generating $@'
-       @$(CONFIG_SHELL) $(obj)/machgen.sh $(obj)/mach-types > $@
-
+       $(Q)$(AWK) -f $^ > $@ || { rm -f $@; /bin/false; }
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");
+       }
index 7d0f422..b0f138f 100644 (file)
@@ -30,9 +30,9 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
+#include <linux/bitops.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/bitops.h>
 #include <asm/smp.h>
 #include <asm/pgalloc.h>
 #include <asm/delay.h>
index 4062ae5..43f88f3 100644 (file)
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
+#include <linux/bitops.h>       /* this includes also <asm/registers.h */
+                                /* which is required to remap register */
+                                /* names used into __asm__ blocks...   */
 
 #include <asm/hardware.h>
 #include <asm/platform.h>
-#include <asm/bitops.h>                /* this includes also <asm/registers.h */
-                               /* which is required to remap register */
-                               /* names used into __asm__ blocks...   */
 #include <asm/page.h>
 #include <asm/io.h>
 #include <asm/irq.h>
index 842a243..368cab7 100644 (file)
@@ -517,7 +517,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
                bus->resource[0]->flags |= IORESOURCE_IO;
                bus->resource[1]->flags |= IORESOURCE_MEM;
 
-               /* For now, propogate host limits to the bus;
+               /* For now, propagate host limits to the bus;
                 * we'll adjust them later. */
 
 #if 1
index 13cec35..9f46fbc 100644 (file)
@@ -765,9 +765,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        childregs->regs[9] = 0; /* Set return value for child */
        childregs->sr |= SR_FD; /* Invalidate FPU flag */
 
-       /* From sh */
-       p->set_child_tid = p->clear_child_tid = NULL;
-
        p->thread.sp = (unsigned long) childregs;
        p->thread.pc = (unsigned long) ret_from_fork;
 
@@ -862,8 +859,11 @@ asmlinkage int sys_execve(char *ufilename, char **uargv,
                          (char __user * __user *)uargv,
                          (char __user * __user *)uenvp,
                          pregs);
-       if (error == 0)
+       if (error == 0) {
+               task_lock(current);
                current->ptrace &= ~PT_DTRACE;
+               task_unlock(current);
+       }
        putname(filename);
 out:
        unlock_kernel();
index c48bc4a..f27c696 100644 (file)
@@ -257,7 +257,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
  */
        case PTRACE_KILL: {
                ret = 0;
-               if (child->state == TASK_ZOMBIE)        /* already dead */
+               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
                        break;
                child->exit_code = SIGKILL;
                wake_up_process(child);
index b3738ed..9d73104 100644 (file)
@@ -309,6 +309,9 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
        ctc_last_interrupt = (unsigned long) current_ctc;
 
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
        profile_tick(CPU_PROFILING, regs);
 
 #ifdef CONFIG_HEARTBEAT
index 44b6dd7..4bb41a1 100644 (file)
@@ -17,7 +17,7 @@
 /* auxio_register is not static because it is referenced 
  * in entry.S::floppy_tdone
  */
-unsigned long auxio_register = 0UL;
+void __iomem *auxio_register = NULL;
 static spinlock_t auxio_lock = SPIN_LOCK_UNLOCKED;
 
 void __init auxio_probe(void)
@@ -63,7 +63,7 @@ void __init auxio_probe(void)
        /* Fix the address on sun4m and sun4c. */
        if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
           sparc_cpu_model == sun4c)
-               auxio_register |= 3;
+               auxio_register += (3 - ((unsigned long)auxio_register & 3));
 
        set_auxio(AUXIO_LED, 0);
 }
index 624e2a6..b448166 100644 (file)
@@ -38,7 +38,7 @@
 
 #define curptr      g6
 
-#define NR_SYSCALLS 283      /* Each OS is different... */
+#define NR_SYSCALLS 284      /* Each OS is different... */
 
 /* These are just handy. */
 #define _SV    save    %sp, -STACKFRAME_SZ, %sp
@@ -1508,7 +1508,7 @@ syscall_is_too_hard:
        .globl  ret_sys_call
 ret_sys_call:
        ld      [%curptr + TI_FLAGS], %l6
-       cmp     %o0, -ENOIOCTLCMD
+       cmp     %o0, -ERESTART_RESTARTBLOCK
        ld      [%sp + STACKFRAME_SZ + PT_PSR], %g3
        set     PSR_C, %g2
        bgeu    1f
@@ -1587,7 +1587,7 @@ solaris_syscall:
 
        st      %o0, [%sp + STACKFRAME_SZ + PT_I0]
        set     PSR_C, %g2
-       cmp     %o0, -ENOIOCTLCMD
+       cmp     %o0, -ERESTART_RESTARTBLOCK
        bgeu    1f
         ld     [%sp + STACKFRAME_SZ + PT_PSR], %g3
 
@@ -1678,7 +1678,7 @@ bsd_is_too_hard:
 
        st      %o0, [%sp + STACKFRAME_SZ + PT_I0]
        set     PSR_C, %g2
-       cmp     %o0, -ENOIOCTLCMD
+       cmp     %o0, -ERESTART_RESTARTBLOCK
        bgeu    1f
         ld     [%sp + STACKFRAME_SZ + PT_PSR], %g3
 
index c982473..f8ccbfc 100644 (file)
@@ -603,7 +603,7 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
  */
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
-       struct list_head *walk;
+       struct pci_dev *dev;
        int i, has_io, has_mem;
        unsigned int cmd;
        struct linux_pcic *pcic;
@@ -625,9 +625,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
                return;
        }
 
-       walk = &bus->devices;
-       for (walk = walk->next; walk != &bus->devices; walk = walk->next) {
-               struct pci_dev *dev = pci_dev_b(walk);
+       list_for_each_entry(dev, &bus->devices, bus_list) {
 
                /*
                 * Comment from i386 branch:
@@ -716,6 +714,9 @@ static irqreturn_t pcic_timer_handler (int irq, void *h, struct pt_regs *regs)
        write_seqlock(&xtime_lock);     /* Dummy, to show that we remember */
        pcic_clear_clock_irq();
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
        write_sequnlock(&xtime_lock);
        return IRQ_HANDLED;
 }
index 869c2f1..7eca887 100644 (file)
@@ -30,7 +30,7 @@
 #define PMC_IDLE_REG   0x00
 #define PMC_IDLE_ON            0x01
 
-volatile static u8 *regs; 
+volatile static u8 __iomem *regs; 
 static int pmc_regsize;
 
 #define pmc_readb(offs)                        (sbus_readb(regs+offs))
@@ -55,7 +55,7 @@ void pmc_swift_idle(void)
 
 static inline void pmc_free(void)
 {
-       sbus_iounmap((unsigned long)regs, pmc_regsize);
+       sbus_iounmap(regs, pmc_regsize);
 }
 
 static int __init pmc_probe(void)
@@ -76,9 +76,9 @@ sbus_done:
        }
 
        pmc_regsize = sdev->reg_addrs[0].reg_size;
-       regs = (u8*) sbus_ioremap(&sdev->resource[0], 0, 
+       regs = sbus_ioremap(&sdev->resource[0], 0, 
                                   pmc_regsize, PMC_OBPNAME);
-       if(NULL == regs) {
+       if (!regs) {
                printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME);
                return -ENODEV;
        }
index f375c8e..1e711bb 100644 (file)
@@ -10,9 +10,9 @@
  */
 
 #include <linux/smp_lock.h>
+#include <linux/bitops.h>
 
 #include <asm/bitext.h>
-#include <asm/bitops.h>
 
 /**
  * bit_map_string_get - find and set a bit string in bit map.
index 6d2febb..f4c6851 100644 (file)
@@ -41,7 +41,7 @@ static inline void forget_pte(pte_t page)
 #endif
 }
 
-/* Remap IO memory, the same way as remap_page_range(), but use
+/* Remap IO memory, the same way as remap_pfn_range(), but use
  * the obio memory space.
  *
  * They use a pgprot that sets PAGE_IO and does not check the
index d5593b5..b873e84 100644 (file)
@@ -1463,6 +1463,7 @@ static void __init poke_hypersparc(void)
 static void __init init_hypersparc(void)
 {
        srmmu_name = "ROSS HyperSparc";
+       srmmu_modtype = HyperSparc;
 
        init_vac_layout();
 
index fb3e3b7..c13eaf0 100644 (file)
@@ -79,7 +79,7 @@ typedef struct {
 
 #define elf_check_arch(x)      (((x)->e_machine == EM_SPARC) || ((x)->e_machine == EM_SPARC32PLUS))
 
-#define ELF_ET_DYN_BASE         0x08000000
+#define ELF_ET_DYN_BASE         0x70000000
 
 
 #include <asm/processor.h>
index 8ad5077..30862ab 100644 (file)
@@ -262,7 +262,7 @@ void __init isa_init(void)
        device = PCI_DEVICE_ID_AL_M1533;
 
        pdev = NULL;
-       while ((pdev = pci_find_device(vendor, device, pdev)) != NULL) {
+       while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) {
                struct pcidev_cookie *pdev_cookie;
                struct pci_pbm_info *pbm;
                struct sparc_isa_bridge *isa_br;
index bc5cc1d..801ab91 100644 (file)
@@ -15,7 +15,7 @@
  * traps.  The top-level scheme is similar to that used
  * in the x86 kprobes implementation.
  *
- * In the kprobe->insn[] array we store the original
+ * In the kprobe->ainsn.insn[] array we store the original
  * instruction at index zero and a break instruction at
  * index one.
  *
  * - 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]
+ * - Set regs->tpc to point to kprobe->ainsn.insn[0]
+ * - Set regs->tnpc to point to kprobe->ainsn.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:
+ * kprobe->ainsn.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
  * - Mark that we are no longer actively in a kprobe.
  */
 
-void arch_prepare_kprobe(struct kprobe *p)
+int arch_prepare_kprobe(struct kprobe *p)
+{
+       p->ainsn.insn[0] = *p->addr;
+       p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
+       return 0;
+}
+
+void arch_remove_kprobe(struct kprobe *p)
 {
-       p->insn[0] = *p->addr;
-       p->insn[1] = BREAKPOINT_INSTRUCTION_2;
 }
 
 /* kprobe_status settings */
@@ -59,8 +64,8 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
        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];
+       regs->tpc = (unsigned long) &p->ainsn.insn[0];
+       regs->tnpc = (unsigned long) &p->ainsn.insn[1];
 }
 
 static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
@@ -199,19 +204,19 @@ static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc)
  * 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.
+ * copy is p->ainsn.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];
+       u32 insn = p->ainsn.insn[0];
 
        regs->tpc = current_kprobe_orig_tnpc;
        regs->tnpc = relbranch_fixup(insn,
                                     (unsigned long) p->addr,
-                                    (unsigned long) &p->insn[0],
+                                    (unsigned long) &p->ainsn.insn[0],
                                     regs->tnpc);
        retpc_fixup(regs, insn, (unsigned long) p->addr);
 
index 94a5298..2929834 100644 (file)
@@ -814,7 +814,7 @@ static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
        /* ALI sound chips generate 31-bits of DMA, a special register
         * determines what bit 31 is emitted as.
         */
-       ali_isa_bridge = pci_find_device(PCI_VENDOR_ID_AL,
+       ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL,
                                         PCI_DEVICE_ID_AL_M1533,
                                         NULL);
 
@@ -824,6 +824,7 @@ static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
        else
                val &= ~0x01;
        pci_write_config_byte(ali_isa_bridge, 0x7e, val);
+       pci_dev_put(ali_isa_bridge);
 }
 
 int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
index 28fe12b..f1d764b 100644 (file)
@@ -90,7 +90,9 @@ startup_continue:
        sllx            %g2, 32, %g2
        wr              %g2, 0, %tick_cmpr
 
-       /* Call OBP by hand to lock KERNBASE into i/d tlbs. */
+       /* Call OBP by hand to lock KERNBASE into i/d tlbs.
+        * We lock 2 consequetive entries if we are 'bigkernel'.
+        */
        mov             %o0, %l0
 
        sethi           %hi(prom_entry_lock), %g2
@@ -136,6 +138,46 @@ startup_continue:
        call            %o1
         add            %sp, (2047 + 128), %o0
 
+       sethi           %hi(bigkernel), %g2
+       lduw            [%g2 + %lo(bigkernel)], %g2
+       cmp             %g2, 0
+       be,pt           %icc, do_dtlb
+        nop
+
+       sethi           %hi(call_method), %g2
+       or              %g2, %lo(call_method), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x00]
+       mov             5, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x08]
+       mov             1, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x10]
+       sethi           %hi(itlb_load), %g2
+       or              %g2, %lo(itlb_load), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x18]
+       sethi           %hi(mmu_ihandle_cache), %g2
+       lduw            [%g2 + %lo(mmu_ihandle_cache)], %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x20]
+       sethi           %hi(KERNBASE + 0x400000), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x28]
+       sethi           %hi(kern_locked_tte_data), %g2
+       ldx             [%g2 + %lo(kern_locked_tte_data)], %g2
+       sethi           %hi(0x400000), %g1
+       add             %g2, %g1, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x30]
+
+       mov             14, %g2
+       BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
+
+       mov             62, %g2
+1:
+       stx             %g2, [%sp + 2047 + 128 + 0x38]
+       sethi           %hi(p1275buf), %g2
+       or              %g2, %lo(p1275buf), %g2
+       ldx             [%g2 + 0x08], %o1
+       call            %o1
+        add            %sp, (2047 + 128), %o0
+
+do_dtlb:
        sethi           %hi(call_method), %g2
        or              %g2, %lo(call_method), %g2
        stx             %g2, [%sp + 2047 + 128 + 0x00]
@@ -168,6 +210,47 @@ startup_continue:
        call            %o1
         add            %sp, (2047 + 128), %o0
 
+       sethi           %hi(bigkernel), %g2
+       lduw            [%g2 + %lo(bigkernel)], %g2
+       cmp             %g2, 0
+       be,pt           %icc, do_unlock
+        nop
+
+       sethi           %hi(call_method), %g2
+       or              %g2, %lo(call_method), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x00]
+       mov             5, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x08]
+       mov             1, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x10]
+       sethi           %hi(dtlb_load), %g2
+       or              %g2, %lo(dtlb_load), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x18]
+       sethi           %hi(mmu_ihandle_cache), %g2
+       lduw            [%g2 + %lo(mmu_ihandle_cache)], %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x20]
+       sethi           %hi(KERNBASE + 0x400000), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x28]
+       sethi           %hi(kern_locked_tte_data), %g2
+       ldx             [%g2 + %lo(kern_locked_tte_data)], %g2
+       sethi           %hi(0x400000), %g1
+       add             %g2, %g1, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x30]
+
+       mov             14, %g2
+       BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
+
+       mov             62, %g2
+1:
+
+       stx             %g2, [%sp + 2047 + 128 + 0x38]
+       sethi           %hi(p1275buf), %g2
+       or              %g2, %lo(p1275buf), %g2
+       ldx             [%g2 + 0x08], %o1
+       call            %o1
+        add            %sp, (2047 + 128), %o0
+
+do_unlock:
        sethi           %hi(prom_entry_lock), %g2
        stb             %g0, [%g2 + %lo(prom_entry_lock)]
        membar          #StoreStore | #StoreLoad
index 399c135..e869067 100644 (file)
@@ -25,8 +25,8 @@
         * }
         */
 
-       .globl  atomic_dec_and_lock
-atomic_dec_and_lock:   /* %o0 = counter, %o1 = lock */
+       .globl  _atomic_dec_and_lock
+_atomic_dec_and_lock:  /* %o0 = counter, %o1 = lock */
 loop1: lduw    [%o0], %g5
        subcc   %g5, 1, %g7
        be,pn   %icc, start_to_zero
index 149dc1b..6be13eb 100644 (file)
 #include <asm/page.h>
 #include <asm/tlbflush.h>
 
-static inline void forget_pte(pte_t page)
-{
-       if (!pte_none(page)) {
-               printk("forget_pte: old mapping existed!\n");
-               BUG();
-       }
-}
-
-/* Remap IO memory, the same way as remap_page_range(), but use
+/* Remap IO memory, the same way as remap_pfn_range(), but use
  * the obio memory space.
  *
  * They use a pgprot that sets PAGE_IO and does not check the
@@ -43,7 +35,6 @@ static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsign
        if (end > PMD_SIZE)
                end = PMD_SIZE;
        do {
-               pte_t oldpage;
                pte_t entry;
                unsigned long curend = address + PAGE_SIZE;
                
@@ -75,10 +66,8 @@ static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsign
                if (offset & 0x1UL)
                        pte_val(entry) &= ~(_PAGE_E);
                do {
-                       oldpage = *pte;
-                       pte_clear(pte);
+                       BUG_ON(!pte_none(*pte));
                        set_pte(pte, entry);
-                       forget_pte(oldpage);
                        address += PAGE_SIZE;
                        pte++;
                } while (address < curend);
@@ -132,8 +121,8 @@ int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned
                from = (from + PGDIR_SIZE) & PGDIR_MASK;
                dir++;
        }
+       flush_tlb_range(vma, beg, end);
        spin_unlock(&mm->page_table_lock);
 
-       flush_tlb_range(vma, beg, end);
        return error;
 }
index ba04530..0cc9dad 100644 (file)
@@ -109,7 +109,7 @@ ret_from_solaris:
        sra             %o0, 0, %o0
        mov             %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
        ldx             [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
-       cmp             %o0, -ENOIOCTLCMD
+       cmp             %o0, -ERESTART_RESTARTBLOCK
        sllx            %g2, 32, %g2
        bgeu,pn         %xcc, 1f
         andcc          %l6, _TIF_SYSCALL_TRACE, %l6    
index 853afe9..d25667e 100644 (file)
@@ -295,4 +295,20 @@ solaris_sys_table:
        .word solaris_unimplemented     /*                      265     */
        .word solaris_unimplemented     /*                      266     */
        .word solaris_unimplemented     /*                      267     */
+       .word solaris_unimplemented     /*                      268     */
+       .word solaris_unimplemented     /*                      269     */
+       .word solaris_unimplemented     /*                      270     */
+       .word solaris_unimplemented     /*                      271     */
+       .word solaris_unimplemented     /*                      272     */
+       .word solaris_unimplemented     /*                      273     */
+       .word solaris_unimplemented     /*                      274     */
+       .word solaris_unimplemented     /*                      275     */
+       .word solaris_unimplemented     /*                      276     */
+       .word solaris_unimplemented     /*                      277     */
+       .word solaris_unimplemented     /*                      278     */
+       .word solaris_unimplemented     /*                      279     */
+       .word solaris_unimplemented     /*                      280     */
+       .word solaris_unimplemented     /*                      281     */
+       .word solaris_unimplemented     /*                      282     */
+       .word solaris_unimplemented     /*                      283     */
 
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__
index d3fad24..122664b 100644 (file)
@@ -67,7 +67,7 @@ struct cow_header_v2 {
 struct cow_header_v3 {
        __u32 magic;
        __u32 version;
-       time_t mtime;
+       __u32 mtime;
        __u64 size;
        __u32 sectorsize;
        __u32 alignment;
index 21becc6..b67ea3e 100644 (file)
 #include "sysdep/frame_kern.h"
 
 extern int setup_signal_stack_sc(unsigned long stack_top, int sig, 
-                                unsigned long handler,
-                                void (*restorer)(void), 
+                                struct k_sigaction *ka,
                                 struct pt_regs *regs, 
                                 sigset_t *mask);
 extern int setup_signal_stack_si(unsigned long stack_top, int sig, 
-                                unsigned long handler, 
-                                void (*restorer)(void), 
+                                struct k_sigaction *ka,
                                 struct pt_regs *regs, siginfo_t *info, 
                                 sigset_t *mask);
 
index 23b95f9..786cf56 100644 (file)
@@ -9,11 +9,11 @@
 #include "uml-config.h"
 
 #ifdef UML_CONFIG_MODE_TT
-#include "../kernel/tt/include/mode.h"
+#include "mode-tt.h"
 #endif
 
 #ifdef UML_CONFIG_MODE_SKAS
-#include "../kernel/skas/include/mode.h"
+#include "mode-skas.h"
 #endif
 
 #endif
index 562174b..2d88afd 100644 (file)
@@ -9,11 +9,11 @@
 #include "linux/config.h"
 
 #ifdef CONFIG_MODE_TT
-#include "../kernel/tt/include/mode_kern.h"
+#include "mode_kern-tt.h"
 #endif
 
 #ifdef CONFIG_MODE_SKAS
-#include "../kernel/skas/include/mode_kern.h"
+#include "mode_kern-skas.h"
 #endif
 
 #endif
index ad35d0c..227cef5 100644 (file)
@@ -15,4 +15,15 @@ extern void arch_enter_kernel(void *task, int pid);
 extern void arch_leave_kernel(void *task, int pid);
 extern void ptrace_pokeuser(unsigned long addr, unsigned long data);
 
+
+/* syscall emulation path in ptrace */
+
+#ifndef PTRACE_SYSEMU
+#define PTRACE_SYSEMU 31
+#endif
+
+void set_using_sysemu(int value);
+int get_using_sysemu(void);
+extern int sysemu_supported;
+
 #endif
index bc7be62..811d0ec 100644 (file)
@@ -7,7 +7,7 @@
 #define __SYSCALL_USER_H
 
 extern int record_syscall_start(int syscall);
-extern void record_syscall_end(int index, int result);
+extern void record_syscall_end(int index, long result);
 
 #endif
 
index 3c5660f..5243f45 100644 (file)
 #include "choose-mode.h"
 
 #ifdef CONFIG_MODE_TT
-#include "../kernel/tt/include/mmu.h"
+#include "mmu-tt.h"
 #endif
 
 #ifdef CONFIG_MODE_SKAS
-#include "../kernel/skas/include/mmu.h"
+#include "mmu-skas.h"
 #endif
 
 typedef union {
index ee16421..39ddb09 100644 (file)
@@ -59,6 +59,8 @@ SECTIONS
   .text           : {
     *(.text)
     SCHED_TEXT
+    LOCK_TEXT
+    *(.fixup)
     *(.stub .text.* .gnu.linkonce.t.*)
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
index e1fd2c5..3011804 100644 (file)
 #include "kern_util.h"
 #include "mem_user.h"
 #include "signal_user.h"
+#include "time_user.h"
+#include "irq_user.h"
 #include "user.h"
 #include "init.h"
 #include "mode.h"
 #include "choose-mode.h"
 #include "uml-config.h"
+#include "irq_user.h"
+#include "time_user.h"
+#include "os.h"
 
 /* Set in set_stklim, which is called from main and __wrap_malloc.
  * __wrap_malloc only calls it if main hasn't started.
@@ -171,7 +176,7 @@ int main(int argc, char **argv, char **envp)
 }
 
 #define CAN_KMALLOC() \
-       (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1))
+       (kmalloc_ok && CHOOSE_MODE((os_getpid() != tracing_pid), 1))
 
 extern void *__real_malloc(int);
 
index 74a69e4..2468cd6 100644 (file)
@@ -57,6 +57,10 @@ int change_sig(int signal, int on)
        return(!sigismember(&old, signal));
 }
 
+/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
+ * disable profiling; it's safe because the profiling code does not interact
+ * with the kernel code at all.*/
+
 static void change_signals(int type)
 {
        sigset_t mask;
@@ -65,7 +69,6 @@ static void change_signals(int type)
        sigaddset(&mask, SIGVTALRM);
        sigaddset(&mask, SIGALRM);
        sigaddset(&mask, SIGIO);
-       sigaddset(&mask, SIGPROF);
        if(sigprocmask(type, &mask, NULL) < 0)
                panic("Failed to change signal mask - errno = %d", errno);
 }
index 49356d2..c6b4d5d 100644 (file)
@@ -12,7 +12,7 @@
 #include "asm/mmu_context.h"
 #include "tlb.h"
 #include "skas.h"
-#include "mmu.h"
+#include "um_mmu.h"
 #include "os.h"
 
 void flush_thread_skas(void)
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:
+ */
index 3712286..01b711e 100644 (file)
@@ -11,7 +11,7 @@
 struct {
        int syscall;
        int pid;
-       int result;
+       long result;
        struct timeval start;
        struct timeval end;
 } syscall_record[1024];
@@ -30,7 +30,7 @@ int record_syscall_start(int syscall)
        return(index);
 }
 
-void record_syscall_end(int index, int result)
+void record_syscall_end(int index, long result)
 {
        syscall_record[index].result = result;
        gettimeofday(&syscall_record[index].end, NULL);
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:
+ */
index b7c4745..e6d64eb 100644 (file)
@@ -24,11 +24,9 @@ extern void set_init_pid(int pid);
 extern int set_user_mode(void *task);
 extern void set_tracing(void *t, int tracing);
 extern int is_tracing(void *task);
-extern int singlestepping_tt(void *t);
-extern void clear_singlestep(void *t);
 extern void syscall_handler(int sig, union uml_pt_regs *regs);
 extern void exit_kernel(int pid, void *task);
-extern int do_syscall(void *task, int pid);
+extern int do_syscall(void *task, int pid, int local_using_sysemu);
 extern int is_valid_pid(int pid);
 extern void remap_data(void *segment_start, void *segment_end, int w);
 
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:
+ */
index 89ed329..72b608c 100644 (file)
@@ -35,6 +35,8 @@ SECTIONS
   {
     *(.text)
     SCHED_TEXT
+    LOCK_TEXT
+    *(.fixup)
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
     *(.gnu.linkonce.t*)
index 817ef74..42322d8 100644 (file)
@@ -7,6 +7,7 @@
 #include "asm/elf.h"
 #include "asm/ptrace.h"
 #include "asm/uaccess.h"
+#include "asm/unistd.h"
 #include "ptrace_user.h"
 #include "sysdep/sigcontext.h"
 #include "sysdep/sc.h"
@@ -23,11 +24,12 @@ int is_syscall(unsigned long addr)
 
        n = copy_from_user(&instr, (void *) addr, sizeof(instr));
        if(n){
-               printk("is_syscall : failed to read instruction from 0x%lu\n", 
+               printk("is_syscall : failed to read instruction from 0x%lx\n",
                       addr);
                return(0);
        }
-       return(instr == 0x80cd);
+       /* int 0x80 or sysenter */
+       return((instr == 0x80cd) || (instr == 0x340f));
 }
 
 /* determines which flags the user has access to. */
index 5133333..281fc7b 100644 (file)
@@ -1,3 +1,8 @@
+/*
+ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
 #include "linux/kernel.h"
 #include "linux/smp.h"
 #include "linux/sched.h"
index 9bd818b..673b509 100644 (file)
@@ -88,8 +88,7 @@ int memcons_tty_open (struct tty_struct *tty, struct file *filp)
        return 0;
 }
 
-int memcons_tty_write (struct tty_struct *tty, int from_user,
-                      const unsigned char *buf, int len)
+int memcons_tty_write (struct tty_struct *tty, const unsigned char *buf, int len)
 {
        return write (buf, len);
 }
index 551c41b..78a9cad 100644 (file)
@@ -254,7 +254,7 @@ static void __devinit pcibios_assign_resources (void)
        struct pci_dev *dev = NULL;
        struct resource *r;
 
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                unsigned di_num;
                unsigned class = dev->class >> 8;
 
index 60098e4..9432ff8 100644 (file)
@@ -427,11 +427,9 @@ give_sigsegv:
  */    
 
 static void
-handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
-       struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
+             sigset_t *oldset, struct pt_regs * regs)
 {
-       struct k_sigaction *ka = &current->sighand->action[sig-1];
-
        /* Are we from a system call? */
        if (PT_REGS_SYSCALL (regs)) {
                /* If so, check system call restarting.. */
@@ -464,9 +462,6 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (ka->sa.sa_flags & SA_ONESHOT)
-               ka->sa.sa_handler = SIG_DFL;
-
        if (!(ka->sa.sa_flags & SA_NODEFER)) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -489,6 +484,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
        siginfo_t info;
        int signr;
+       struct k_sigaction ka;
 
        /*
         * We want the common case to go fast, which
@@ -502,10 +498,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
        if (!oldset)
                oldset = &current->blocked;
 
-       signr = get_signal_to_deliver(&info, regs, NULL);
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &info, oldset, regs);
+               handle_signal(signr, &info, &ka, oldset, regs);
                return 1;
        }
 
index 9aed887..7f0efaa 100644 (file)
@@ -59,7 +59,7 @@ int simcons_tty_open (struct tty_struct *tty, struct file *filp)
        return 0;
 }
 
-int simcons_tty_write (struct tty_struct *tty, int from_user,
+int simcons_tty_write (struct tty_struct *tty,
                       const unsigned char *buf, int count)
 {
        return V850_SIM_SYSCALL (write, 1, buf, count);
index 2ba7f5a..9cf1410 100644 (file)
@@ -18,18 +18,6 @@ config INIT_DEBUG
          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"
@@ -45,6 +33,16 @@ config IOMMU_DEBUG
         options. See Documentation/x86_64/boot-options.txt for more
         details.
 
+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 IOMMU_LEAK
        bool "IOMMU leak tracing"
        depends on DEBUG_KERNEL
index 99b7904..f4399c7 100644 (file)
@@ -31,6 +31,7 @@ targets               := vmlinux.bin bootsect bootsect.o \
 EXTRA_CFLAGS := -m32
 
 hostprogs-y    := tools/build
+HOST_EXTRACFLAGS += $(LINUXINCLUDE)
 subdir-                := compressed/  #Let make clean descend in compressed/
 # ---------------------------------------------------------------------------
 
index 759956d..f89d96f 100644 (file)
@@ -11,7 +11,7 @@ EXTRA_AFLAGS  := -traditional -m32
 
 # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with
 # -m32
-CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2  
+CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2  -fno-strict-aliasing
 LDFLAGS := -m elf_i386
 
 LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386
index dcb518e..acaf62a 100644 (file)
@@ -4,18 +4,6 @@
 
 menu "CPU Frequency scaling"
 
-config CPU_FREQ
-       bool "CPU Frequency scaling"
-       help
-         Clock scaling allows you to change the clock speed of CPUs on the
-         fly. This is a nice method to save battery power on notebooks,
-         because the lower the clock speed, the less power the CPU consumes.
-
-         For more information, take a look at <file:Documentation/cpu-freq/>
-         or at <http://www.codemonkey.org.uk/projects/cpufreq/>
-
-         If in doubt, say N.
-
 source "drivers/cpufreq/Kconfig"
 
 config CPU_FREQ_TABLE
@@ -48,7 +36,7 @@ config X86_POWERNOW_K8_ACPI
 
 config X86_SPEEDSTEP_CENTRINO
        tristate "Intel Enhanced SpeedStep"
-       depends on CPU_FREQ_TABLE
+       depends on CPU_FREQ_TABLE && ACPI_PROCESSOR
        help
          This adds the CPUFreq driver for Enhanced SpeedStep enabled
          mobile CPUs.  This means Intel Pentium M (Centrino) CPUs
@@ -58,21 +46,11 @@ config X86_SPEEDSTEP_CENTRINO
 
          If in doubt, say N.
 
-config X86_SPEEDSTEP_CENTRINO_TABLE
+config X86_SPEEDSTEP_CENTRINO_ACPI
        bool
        depends on X86_SPEEDSTEP_CENTRINO
        default y
 
-config X86_SPEEDSTEP_CENTRINO_ACPI
-       bool "Use ACPI tables to decode valid frequency/voltage pairs (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
-       depends on ((X86_SPEEDSTEP_CENTRINO = "m" && ACPI_PROCESSOR) || (X86_SPEEDSTEP_CENTRINO = "y" && ACPI_PROCESSOR = "y"))
-       help
-         Use primarily the information provided in the BIOS ACPI tables
-         to determine valid CPU frequency and voltage pairings.
-
-         If in doubt, say Y.
-
 config X86_ACPI_CPUFREQ
        tristate "ACPI Processor P-States driver"
        depends on CPU_FREQ_TABLE && ACPI_PROCESSOR
@@ -84,9 +62,13 @@ config X86_ACPI_CPUFREQ
 
          If in doubt, say N.
 
+comment "shared options"
+       depends on CPU_FREQ
+
 config X86_ACPI_CPUFREQ_PROC_INTF
         bool "/proc/acpi/processor/../performance interface (deprecated)"
-       depends on X86_ACPI_CPUFREQ && PROC_FS
+       depends on PROC_FS
+       depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K8_ACPI
        help
          This enables the deprecated /proc/acpi/processor/../performance
          interface. While it is helpful for debugging, the generic,
@@ -94,5 +76,29 @@ config X86_ACPI_CPUFREQ_PROC_INTF
 
          If in doubt, say N.
 
+config X86_P4_CLOCKMOD
+       tristate "Intel Pentium 4 clock modulation"
+       depends on CPU_FREQ_TABLE && EMBEDDED
+       help
+         This adds the clock modulation driver for Intel Pentium 4 / XEON
+         processors.  When enabled it will lower CPU temperature by skipping
+         clocks.
+
+         This driver should be only used in exceptional
+         circumstances when very low power is needed because it causes severe
+         slowdowns and noticeable latencies.  Normally Speedstep should be used
+         instead.
+
+         For details, take a look at <file:Documentation/cpu-freq/>.
+
+         Unless you are absolutely sure say N.
+
+
+config X86_SPEEDSTEP_LIB
+        tristate
+        depends on (X86_P4_CLOCKMOD)
+        default (X86_P4_CLOCKMOD)
+
+
 endmenu
 
index d0f0b2c..d8b5938 100644 (file)
@@ -6,8 +6,12 @@ SRCDIR := ../../../i386/kernel/cpu/cpufreq
 
 obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
 obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
-obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi.o
+obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o
+obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
+obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o
 
 powernow-k8-objs := ${SRCDIR}/powernow-k8.o
 speedstep-centrino-objs := ${SRCDIR}/speedstep-centrino.o
-acpi-objs := ${SRCDIR}/acpi.o
+acpi-cpufreq-objs := ${SRCDIR}/acpi-cpufreq.o
+p4-clockmod-objs := ${SRCDIR}/p4-clockmod.o
+speedstep-lib-objs := ${SRCDIR}/speedstep-lib.o
index 600ec81..5ed9bd2 100644 (file)
@@ -10,7 +10,7 @@
 #ifdef __i386__
 #define VGABASE                (__ISA_IO_base + 0xb8000)
 #else
-#define VGABASE                0xffffffff800b8000UL
+#define VGABASE                ((void *)0xffffffff800b8000UL)
 #endif
 
 #define MAX_YPOS       25
index 17d74eb..d8d906a 100644 (file)
@@ -907,6 +907,7 @@ ENTRY(divide_error)
 ENTRY(spurious_interrupt_bug)
        zeroentry do_spurious_interrupt_bug
 
+#ifdef CONFIG_X86_MCE
        /* runs on exception stack */
 ENTRY(machine_check)
        CFI_STARTPROC
@@ -915,6 +916,7 @@ ENTRY(machine_check)
        paranoidentry do_machine_check
        jmp paranoid_exit
        CFI_ENDPROC
+#endif
 
 ENTRY(call_debug)
        zeroentry do_call_debug
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;
+               }
+       }
+}
index 4920c8d..143fe2f 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/sysdev.h>
 #include <linux/nmi.h>
+#include <linux/sysctl.h>
 
 #include <asm/smp.h>
 #include <asm/mtrr.h>
@@ -54,7 +55,7 @@ static unsigned int lapic_nmi_owner;
  * -1: the lapic NMI watchdog is disabled, but can be enabled
  */
 int nmi_active;                /* oprofile uses this */
-static int panic_on_timeout;
+int panic_on_timeout;
 
 unsigned int nmi_watchdog = NMI_DEFAULT;
 static unsigned int nmi_hz = HZ;
@@ -344,8 +345,6 @@ void setup_apic_nmi_watchdog(void)
        nmi_active = 1;
 }
 
-static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
-
 /*
  * the best way to detect whether a CPU has a 'hard lockup' problem
  * is to check it's local APIC timer IRQ counts. If they are not
@@ -395,21 +394,7 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
                                alert_counter[cpu] = 0; 
                                return;
                        } 
-                       spin_lock(&nmi_print_lock);
-                       /*
-                        * We are in trouble anyway, lets at least try
-                        * to get a message out.
-                        */
-                       bust_spinlocks(1);
-                       printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu);
-                       show_registers(regs);
-                       if (panic_on_timeout || panic_on_oops)
-                               panic("nmi watchdog");
-                       printk("console shuts up ...\n");
-                       console_silent();
-                       spin_unlock(&nmi_print_lock);
-                       bust_spinlocks(0);
-                       do_exit(SIGSEGV);
+                       die_nmi("NMI Watchdog detected LOCKUP on CPU%d", regs);
                }
        } else {
                last_irq_sums[cpu] = sum;
@@ -447,6 +432,49 @@ void unset_nmi_callback(void)
        nmi_callback = dummy_nmi_callback;
 }
 
+#ifdef CONFIG_SYSCTL
+
+static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
+{
+       unsigned char reason = get_nmi_reason();
+       char buf[64];
+
+       if (!(reason & 0xc0)) {
+               sprintf(buf, "NMI received for unknown reason %02x\n", reason);
+               die_nmi(buf,regs);
+       }
+       return 0;
+}
+
+/*
+ * proc handler for /proc/sys/kernel/unknown_nmi_panic
+ */
+int proc_unknown_nmi_panic(struct ctl_table *table, int write, struct file *file,
+                       void __user *buffer, size_t *length, loff_t *ppos)
+{
+       int old_state;
+
+       old_state = unknown_nmi_panic;
+       proc_dointvec(table, write, file, buffer, length, ppos);
+       if (!!old_state == !!unknown_nmi_panic)
+               return 0;
+
+       if (unknown_nmi_panic) {
+               if (reserve_lapic_nmi() < 0) {
+                       unknown_nmi_panic = 0;
+                       return -EBUSY;
+               } else {
+                       set_nmi_callback(unknown_nmi_panic_callback);
+               }
+       } else {
+               release_lapic_nmi();
+               unset_nmi_callback();
+       }
+       return 0;
+}
+
+#endif
+
 EXPORT_SYMBOL(nmi_active);
 EXPORT_SYMBOL(nmi_watchdog);
 EXPORT_SYMBOL(reserve_lapic_nmi);
index 13ec453..f28a07c 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/seqlock.h>
+#include <linux/jiffies.h>
 
 #include <asm/vsyscall.h>
 #include <asm/pgtable.h>
@@ -88,7 +89,7 @@ static force_inline void do_vgettimeofday(struct timeval * tv)
                                 __vxtime.tsc_quot) >> 32;
                        /* See comment in x86_64 do_gettimeofday. */ 
                } else {
-                       usec += ((readl(fix_to_virt(VSYSCALL_HPET) + 0xf0) -
+                       usec += ((readl((void *)fix_to_virt(VSYSCALL_HPET) + 0xf0) -
                                  __vxtime.last) * __vxtime.quot) >> 32;
                }
        } while (read_seqretry(&__xtime_lock, sequence));
@@ -165,14 +166,12 @@ static void __init map_vsyscall(void)
 
 static int __init vsyscall_init(void)
 {
-       if ((unsigned long) &vgettimeofday != VSYSCALL_ADDR(__NR_vgettimeofday))
-               panic("vgettimeofday link addr broken");
-       if ((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime))
-               panic("vtime link addr broken");
-       if (VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))
-               panic("fixmap first vsyscall %lx should be %lx", __fix_to_virt(VSYSCALL_FIRST_PAGE),
-                     VSYSCALL_ADDR(0));
+        BUG_ON(((unsigned long) &vgettimeofday != 
+                     VSYSCALL_ADDR(__NR_vgettimeofday)));
+       BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime));
+       BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)));
        map_vsyscall();
+       sysctl_vsyscall = 1; 
 
        return 0;
 }
index 6060dd9..994d766 100644 (file)
@@ -1,5 +1,5 @@
 #include <linux/module.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 
 #undef find_first_zero_bit
 #undef find_next_zero_bit
index e7ce82a..2467660 100644 (file)
@@ -1,5 +1,5 @@
 #include <linux/module.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 
 /* Find string of zero bits in a bitmap */ 
 unsigned long 
index ffd4869..ab43394 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
-int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
        int counter;
        int newcount;
index 0825e37..96cf212 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/module.h>
+#include <linux/nodemask.h>
 #include <asm/io.h>
 #include <linux/pci_ids.h>
 #include <asm/types.h>
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");
index b6bea82..83d5755 100644 (file)
@@ -316,7 +316,7 @@ static const u32 bf_sbox[256 * 4] = {
  * The blowfish encipher, processes 64-bit blocks.
  * NOTE: This function MUSTN'T respect endianess 
  */
-static inline void encrypt_block(struct bf_ctx *bctx, u32 *dst, u32 *src)
+static void encrypt_block(struct bf_ctx *bctx, u32 *dst, u32 *src)
 {
        const u32 *P = bctx->p;
        const u32 *S = bctx->s;
index 9802b1c..4c95ba9 100644 (file)
@@ -4,6 +4,10 @@
  * Serpent Cipher Algorithm.
  *
  * Copyright (C) 2002 Dag Arne Osvik <osvik@ii.uib.no>
+ *               2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * Added tnepres support: Ruben Jesus Garcia Hernandez <ruben@ugr.es>, 18.10.2004
+ *               Based on code by hvr
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -212,7 +216,8 @@ struct serpent_ctx {
        u32 expkey[SERPENT_EXPKEY_WORDS];
 };
 
-static int setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+
+static int serpent_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
 {
        u32 *k = ((struct serpent_ctx *)ctx)->expkey;
        u8  *k8 = (u8 *)k;
@@ -362,7 +367,7 @@ static int setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
        return 0;
 }
 
-static void encrypt(void *ctx, u8 *dst, const u8 *src)
+static void serpent_encrypt(void *ctx, u8 *dst, const u8 *src)
 {
        const u32
                *k = ((struct serpent_ctx *)ctx)->expkey,
@@ -420,7 +425,7 @@ static void encrypt(void *ctx, u8 *dst, const u8 *src)
        d[3] = cpu_to_le32(r3);
 }
 
-static void decrypt(void *ctx, u8 *dst, const u8 *src)
+static void serpent_decrypt(void *ctx, u8 *dst, const u8 *src)
 {
        const u32
                *k = ((struct serpent_ctx *)ctx)->expkey,
@@ -483,18 +488,101 @@ static struct crypto_alg serpent_alg = {
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       SERPENT_MIN_KEY_SIZE,
        .cia_max_keysize        =       SERPENT_MAX_KEY_SIZE,
-       .cia_setkey             =       setkey,
-       .cia_encrypt            =       encrypt,
-       .cia_decrypt            =       decrypt } }
+       .cia_setkey             =       serpent_setkey,
+       .cia_encrypt            =       serpent_encrypt,
+       .cia_decrypt            =       serpent_decrypt } }
+};
+
+static int tnepres_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+{
+       u8 rev_key[SERPENT_MAX_KEY_SIZE];
+       int i;
+
+       if ((keylen < SERPENT_MIN_KEY_SIZE)
+           || (keylen > SERPENT_MAX_KEY_SIZE)) {
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       } 
+
+       for (i = 0; i < keylen; ++i)
+               rev_key[keylen - i - 1] = key[i];
+       return serpent_setkey(ctx, rev_key, keylen, flags);
+}
+
+static void tnepres_encrypt(void *ctx, u8 *dst, const u8 *src)
+{
+       const u32 * const s = (const u32 * const)src;
+       u32 * const d = (u32 * const)dst;
+
+       u32 rs[4], rd[4];
+
+       rs[0] = swab32(s[3]);
+       rs[1] = swab32(s[2]);
+       rs[2] = swab32(s[1]);
+       rs[3] = swab32(s[0]);
+
+       serpent_encrypt(ctx, (u8 *)rd, (u8 *)rs);
+
+       d[0] = swab32(rd[3]);
+       d[1] = swab32(rd[2]);
+       d[2] = swab32(rd[1]);
+       d[3] = swab32(rd[0]);
+}
+
+static void tnepres_decrypt(void *ctx, u8 *dst, const u8 *src)
+{
+       const u32 * const s = (const u32 * const)src;
+       u32 * const d = (u32 * const)dst;
+
+       u32 rs[4], rd[4];
+
+       rs[0] = swab32(s[3]);
+       rs[1] = swab32(s[2]);
+       rs[2] = swab32(s[1]);
+       rs[3] = swab32(s[0]);
+
+       serpent_decrypt(ctx, (u8 *)rd, (u8 *)rs);
+
+       d[0] = swab32(rd[3]);
+       d[1] = swab32(rd[2]);
+       d[2] = swab32(rd[1]);
+       d[3] = swab32(rd[0]);
+}
+
+static struct crypto_alg tnepres_alg = {
+       .cra_name               =       "tnepres",
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct serpent_ctx),
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(serpent_alg.cra_list),
+       .cra_u                  =       { .cipher = {
+       .cia_min_keysize        =       SERPENT_MIN_KEY_SIZE,
+       .cia_max_keysize        =       SERPENT_MAX_KEY_SIZE,
+       .cia_setkey             =       tnepres_setkey,
+       .cia_encrypt            =       tnepres_encrypt,
+       .cia_decrypt            =       tnepres_decrypt } }
 };
 
 static int __init init(void)
 {
-       return crypto_register_alg(&serpent_alg);
+       int ret = crypto_register_alg(&serpent_alg);
+
+       if (ret)
+               return ret;
+
+       ret = crypto_register_alg(&tnepres_alg);
+
+       if (ret)
+               crypto_unregister_alg(&serpent_alg);
+
+       return ret;
 }
 
 static void __exit fini(void)
 {
+       crypto_unregister_alg(&tnepres_alg);
        crypto_unregister_alg(&serpent_alg);
 }
 
@@ -502,5 +590,6 @@ module_init(init);
 module_exit(fini);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Serpent Cipher Algorithm");
+MODULE_DESCRIPTION("Serpent and tnepres (kerneli compatible serpent reversed) Cipher Algorithm");
 MODULE_AUTHOR("Dag Arne Osvik <osvik@ii.uib.no>");
+MODULE_ALIAS("tnepres");
index e8adf15..39f5a65 100644 (file)
@@ -63,15 +63,7 @@ static inline u32 RORu32(u32 x, u32 y)
 
 static inline void LOAD_OP(int I, u32 *W, const u8 *input)
 {
-       u32 t1 = input[(4 * I)] & 0xff;
-
-       t1 <<= 8;
-       t1 |= input[(4 * I) + 1] & 0xff;
-       t1 <<= 8;
-       t1 |= input[(4 * I) + 2] & 0xff;
-       t1 <<= 8;
-       t1 |= input[(4 * I) + 3] & 0xff;
-       W[I] = t1;
+       W[I] = __be32_to_cpu( ((u32*)(input))[I] );
 }
 
 static inline void BLEND_OP(int I, u32 *W)
index f1a8dc0..6acaea9 100644 (file)
@@ -30,6 +30,7 @@ struct sha512_ctx {
        u64 state[8];
        u32 count[4];
        u8 buf[128];
+       u64 W[80];
 };
 
 static inline u64 Ch(u64 x, u64 y, u64 z)
@@ -104,34 +105,18 @@ const u64 sha512_K[80] = {
 
 static inline void LOAD_OP(int I, u64 *W, const u8 *input)
 {
-        u64 t1  = input[(8*I)  ] & 0xff;
-        t1 <<= 8;
-        t1 |= input[(8*I)+1] & 0xff;
-        t1 <<= 8;
-        t1 |= input[(8*I)+2] & 0xff;
-        t1 <<= 8;
-        t1 |= input[(8*I)+3] & 0xff;
-        t1 <<= 8;
-        t1 |= input[(8*I)+4] & 0xff;
-        t1 <<= 8;
-        t1 |= input[(8*I)+5] & 0xff;
-        t1 <<= 8;
-        t1 |= input[(8*I)+6] & 0xff;
-        t1 <<= 8;
-        t1 |= input[(8*I)+7] & 0xff;
-        W[I] = t1;
+       W[I] = __be64_to_cpu( ((u64*)(input))[I] );
 }
 
 static inline void BLEND_OP(int I, u64 *W)
 {
-        W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
+       W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
 }
 
 static void
-sha512_transform(u64 *state, const u8 *input)
+sha512_transform(u64 *state, u64 *W, const u8 *input)
 {
        u64 a, b, c, d, e, f, g, h, t1, t2;
-       u64 W[80];
 
        int i;
 
@@ -172,7 +157,6 @@ sha512_transform(u64 *state, const u8 *input)
 
        /* erase our data */
        a = b = c = d = e = f = g = h = t1 = t2 = 0;
-       memset(W, 0, 80 * sizeof(u64));
 }
 
 static void
@@ -230,10 +214,10 @@ sha512_update(void *ctx, const u8 *data, unsigned int len)
        /* Transform as many times as possible. */
        if (len >= part_len) {
                memcpy(&sctx->buf[index], data, part_len);
-               sha512_transform(sctx->state, sctx->buf);
+               sha512_transform(sctx->state, sctx->W, sctx->buf);
 
                for (i = part_len; i + 127 < len; i+=128)
-                       sha512_transform(sctx->state, &data[i]);
+                       sha512_transform(sctx->state, sctx->W, &data[i]);
 
                index = 0;
        } else {
@@ -242,6 +226,9 @@ sha512_update(void *ctx, const u8 *data, unsigned int len)
 
        /* Buffer remaining input */
        memcpy(&sctx->buf[index], &data[i], len - i);
+
+       /* erase our data */
+       memset(sctx->W, 0, sizeof(sctx->W));
 }
 
 static void
index 0e7a399..9cc2e84 100644 (file)
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
+#include <linux/bitops.h>
 
 #include <asm/arch/oldlatches.h>
-#include <asm/bitops.h>
 #include <asm/dma.h>
 #include <asm/hardware.h>
 #include <asm/hardware/ioc.h>
index bcc35ca..e5d1afe 100644 (file)
@@ -12,8 +12,6 @@ endif
 
 EXTRA_CFLAGS   += $(ACPI_CFLAGS)
 
-obj-$(CONFIG_ACPI)             := acpi_ksyms.o 
-
 #
 # ACPI Boot-Time Table Parsing
 #
@@ -38,6 +36,7 @@ obj-$(CONFIG_ACPI_BATTERY)    += battery.o
 obj-$(CONFIG_ACPI_BUTTON)      += button.o
 obj-$(CONFIG_ACPI_EC)          += ec.o
 obj-$(CONFIG_ACPI_FAN)         += fan.o
+obj-$(CONFIG_ACPI_VIDEO)       += video.o
 obj-$(CONFIG_ACPI_PCI)         += pci_root.o pci_link.o pci_irq.o pci_bind.o
 obj-$(CONFIG_ACPI_POWER)       += power.o
 obj-$(CONFIG_ACPI_PROCESSOR)   += processor.o
@@ -46,5 +45,6 @@ obj-$(CONFIG_ACPI_SYSTEM)     += system.o event.o
 obj-$(CONFIG_ACPI_DEBUG)       += debug.o
 obj-$(CONFIG_ACPI_NUMA)                += numa.o
 obj-$(CONFIG_ACPI_ASUS)                += asus_acpi.o
+obj-$(CONFIG_ACPI_IBM)         += ibm_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
 obj-$(CONFIG_ACPI_BUS)         += scan.o motherboard.o
index befe750..7515477 100644 (file)
@@ -312,7 +312,7 @@ acpi_ds_method_data_set_value (
 
 
        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
-               "obj %p op %X, ref count = %d [%s]\n", object,
+               "new_obj %p Opcode %X, Refs=%d [%s]\n", object,
                opcode, object->common.reference_count,
                acpi_ut_get_type_name (object->common.type)));
 
@@ -350,7 +350,7 @@ acpi_ds_method_data_set_value (
  * RETURN:      Data type of current value of the selected Arg or Local
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_object_type
 acpi_ds_method_data_get_type (
        u16                             opcode,
@@ -385,6 +385,7 @@ acpi_ds_method_data_get_type (
 
        return_VALUE (ACPI_GET_OBJECT_TYPE (object));
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
@@ -448,7 +449,22 @@ acpi_ds_method_data_get_value (
                 * was referenced by the method (via the ASL)
                 * before it was initialized.  Either case is an error.
                 */
-               switch (opcode) {
+
+               /* If slack enabled, init the local_x/arg_x to an Integer of value zero */
+
+               if (acpi_gbl_enable_interpreter_slack) {
+                       object = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+                       if (!object) {
+                               return_ACPI_STATUS (AE_NO_MEMORY);
+                       }
+
+                       object->integer.value = 0;
+                       node->object = object;
+               }
+
+               /* Otherwise, return the error */
+
+               else switch (opcode) {
                case AML_ARG_OP:
 
                        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at node %p\n",
@@ -572,7 +588,7 @@ acpi_ds_store_object_to_local (
 
 
        ACPI_FUNCTION_TRACE ("ds_store_object_to_local");
-       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%d Idx=%d Obj=%p\n",
+       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n",
                opcode, index, obj_desc));
 
        /* Parameter validation */
index 2446278..b18c0df 100644 (file)
@@ -333,7 +333,7 @@ acpi_ds_clear_operands (
        u32                             i;
 
 
-       ACPI_FUNCTION_TRACE_PTR ("acpi_ds_clear_operands", walk_state);
+       ACPI_FUNCTION_TRACE_PTR ("ds_clear_operands", walk_state);
 
 
        /*
index 02872ca..5619660 100644 (file)
  * Dispatch table for opcode classes
  */
 static ACPI_EXECUTE_OP      acpi_gbl_op_type_dispatch [] = {
-                        acpi_ex_opcode_1A_0T_0R,
-                        acpi_ex_opcode_1A_0T_1R,
-                        acpi_ex_opcode_1A_1T_0R,
-                        acpi_ex_opcode_1A_1T_1R,
-                        acpi_ex_opcode_2A_0T_0R,
-                        acpi_ex_opcode_2A_0T_1R,
-                        acpi_ex_opcode_2A_1T_1R,
-                        acpi_ex_opcode_2A_2T_1R,
-                        acpi_ex_opcode_3A_0T_0R,
-                        acpi_ex_opcode_3A_1T_1R,
-                        acpi_ex_opcode_6A_0T_1R};
+                         acpi_ex_opcode_0A_0T_1R,
+                         acpi_ex_opcode_1A_0T_0R,
+                         acpi_ex_opcode_1A_0T_1R,
+                         acpi_ex_opcode_1A_1T_0R,
+                         acpi_ex_opcode_1A_1T_1R,
+                         acpi_ex_opcode_2A_0T_0R,
+                         acpi_ex_opcode_2A_0T_1R,
+                         acpi_ex_opcode_2A_1T_1R,
+                         acpi_ex_opcode_2A_2T_1R,
+                         acpi_ex_opcode_3A_0T_0R,
+                         acpi_ex_opcode_3A_1T_1R,
+                         acpi_ex_opcode_6A_0T_1R};
 
 /*****************************************************************************
  *
@@ -413,7 +414,7 @@ acpi_ds_exec_end_op (
                         * routine.  There is one routine per opcode "type" based upon the
                         * number of opcode arguments and return type.
                         */
-                       status = acpi_gbl_op_type_dispatch [op_type] (walk_state);
+                       status = acpi_gbl_op_type_dispatch[op_type] (walk_state);
                }
                else {
                        /*
@@ -425,7 +426,9 @@ acpi_ds_exec_end_op (
                                (walk_state->operands[0]->common.type == ACPI_TYPE_LOCAL_REFERENCE) &&
                                (walk_state->operands[1]->common.type == ACPI_TYPE_LOCAL_REFERENCE) &&
                                (walk_state->operands[0]->reference.opcode ==
-                                walk_state->operands[1]->reference.opcode)) {
+                                walk_state->operands[1]->reference.opcode) &&
+                               (walk_state->operands[0]->reference.offset ==
+                                walk_state->operands[1]->reference.offset)) {
                                status = AE_OK;
                        }
                        else {
@@ -639,7 +642,8 @@ acpi_ds_exec_end_op (
         * conditional predicate
         */
 
-       if ((walk_state->control_state) &&
+       if ((ACPI_SUCCESS (status)) &&
+               (walk_state->control_state) &&
                (walk_state->control_state->common.state ==
                        ACPI_CONTROL_PREDICATE_EXECUTING) &&
                (walk_state->control_state->control.predicate_op == op)) {
@@ -649,6 +653,19 @@ acpi_ds_exec_end_op (
 
 
 cleanup:
+
+       /* Invoke exception handler on error */
+
+       if (ACPI_FAILURE (status) &&
+               acpi_gbl_exception_handler &&
+               !(status & AE_CODE_CONTROL)) {
+               acpi_ex_exit_interpreter ();
+               status = acpi_gbl_exception_handler (status,
+                                walk_state->method_node->name.integer, walk_state->opcode,
+                                walk_state->aml_offset, NULL);
+               acpi_ex_enter_interpreter ();
+       }
+
        if (walk_state->result_obj) {
                /* Break to debugger to display result */
 
index 9c0d99e..f01f9c4 100644 (file)
@@ -182,18 +182,20 @@ acpi_ds_load1_begin_op (
                 */
                status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
                                  ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
-               if (ACPI_FAILURE (status)) {
 #ifdef _ACPI_ASL_COMPILER
-                       if (status == AE_NOT_FOUND) {
-                               acpi_dm_add_to_external_list (path);
-                               status = AE_OK;
-                       }
-                       else {
-                               ACPI_REPORT_NSERROR (path, status);
-                       }
-#else
-                       ACPI_REPORT_NSERROR (path, status);
+               if (status == AE_NOT_FOUND) {
+                       /*
+                        * Table disassembly:
+                        * Target of Scope() not found.  Generate an External for it, and
+                        * insert the name into the namespace.
+                        */
+                       acpi_dm_add_to_external_list (path);
+                       status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
+                                          ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+               }
 #endif
+               if (ACPI_FAILURE (status)) {
+                       ACPI_REPORT_NSERROR (path, status);
                        return (status);
                }
 
index 81c6b46..5474776 100644 (file)
@@ -51,6 +51,8 @@
         ACPI_MODULE_NAME    ("dswstate")
 
 
+#ifdef ACPI_FUTURE_USAGE
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_result_insert
@@ -174,6 +176,8 @@ acpi_ds_result_remove (
        return (AE_OK);
 }
 
+#endif  /*  ACPI_FUTURE_USAGE  */
+
 
 /*******************************************************************************
  *
@@ -445,7 +449,7 @@ acpi_ds_result_stack_pop (
  *              Should be used with great care, if at all!
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_ds_obj_stack_delete_all (
        struct acpi_walk_state          *walk_state)
@@ -467,6 +471,7 @@ acpi_ds_obj_stack_delete_all (
 
        return_ACPI_STATUS (AE_OK);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
@@ -687,7 +692,7 @@ acpi_ds_obj_stack_pop_and_delete (
  *              be within the range of the current stack pointer.
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 void *
 acpi_ds_obj_stack_get_value (
        u32                             index,
@@ -712,6 +717,7 @@ acpi_ds_obj_stack_get_value (
        return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) -
                          index]);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
@@ -867,6 +873,7 @@ acpi_ds_create_walk_state (
 
        status = acpi_ds_result_stack_push (walk_state);
        if (ACPI_FAILURE (status)) {
+               acpi_ut_release_to_cache (ACPI_MEM_LIST_WALK, walk_state);
                return_PTR (NULL);
        }
 
index afb3688..0c54d31 100644 (file)
@@ -434,13 +434,8 @@ acpi_ev_gpe_detect (
                        }
 
                        ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
-                               "GPE pair: Status %8.8X%8.8X = %02X, Enable %8.8X%8.8X = %02X\n",
-                               ACPI_FORMAT_UINT64 (
-                                       gpe_register_info->status_address.address),
-                                       status_reg,
-                               ACPI_FORMAT_UINT64 (
-                                       gpe_register_info->enable_address.address),
-                                       enable_reg));
+                               "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n",
+                               gpe_register_info->base_gpe_number, status_reg, enable_reg));
 
                        /* First check if there is anything active at all in this register */
 
index 1913f4e..dae8f8c 100644 (file)
@@ -970,16 +970,14 @@ acpi_ev_create_gpe_block (
        /* Dump info about this GPE block */
 
        ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
-               "GPE %02X to %02X [%4.4s] %u regs at %8.8X%8.8X on int 0x%X\n",
+               "GPE %02X to %02X [%4.4s] %u regs on int 0x%X\n",
                (u32) gpe_block->block_base_number,
                (u32) (gpe_block->block_base_number +
                                ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)),
                gpe_device->name.ascii,
                gpe_block->register_count,
-               ACPI_FORMAT_UINT64 (gpe_block->block_address.address),
                interrupt_level));
 
-
        /* Enable all valid GPEs found above */
 
        status = acpi_hw_enable_runtime_gpe_block (NULL, gpe_block);
index e941678..ddd100d 100644 (file)
@@ -41,6 +41,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acevents.h>
@@ -200,6 +201,7 @@ acpi_enable_event (
 
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_enable_event);
 
 
 /*******************************************************************************
@@ -248,6 +250,7 @@ acpi_set_gpe_type (
 unlock_and_exit:
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_set_gpe_type);
 
 
 /*******************************************************************************
@@ -305,6 +308,7 @@ unlock_and_exit:
        }
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_enable_gpe);
 
 
 /*******************************************************************************
@@ -417,6 +421,7 @@ acpi_disable_event (
 
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_disable_event);
 
 
 /*******************************************************************************
@@ -430,7 +435,7 @@ acpi_disable_event (
  * DESCRIPTION: Clear an ACPI event (fixed)
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_clear_event (
        u32                             event)
@@ -456,6 +461,8 @@ acpi_clear_event (
 
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_clear_event);
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
@@ -512,6 +519,8 @@ unlock_and_exit:
 }
 
 
+#ifdef ACPI_FUTURE_USAGE
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_get_event_status
@@ -613,6 +622,7 @@ unlock_and_exit:
        }
        return_ACPI_STATUS (status);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
@@ -705,6 +715,7 @@ unlock_and_exit:
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_install_gpe_block);
 
 
 /*******************************************************************************
@@ -765,4 +776,4 @@ unlock_and_exit:
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS (status);
 }
-
+EXPORT_SYMBOL(acpi_remove_gpe_block);
index 8eeb938..58332cd 100644 (file)
@@ -42,6 +42,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
@@ -116,6 +117,7 @@ unlock_and_exit:
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_install_address_space_handler);
 
 
 /*******************************************************************************
@@ -241,5 +243,5 @@ unlock_and_exit:
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS (status);
 }
-
+EXPORT_SYMBOL(acpi_remove_address_space_handler);
 
index 04c04e4..a29b865 100644 (file)
@@ -58,7 +58,7 @@
  * PARAMETERS:  obj_desc        - Object to be converted.  Must be an
  *                                Integer, Buffer, or String
  *              result_desc     - Where the new Integer object is returned
- *              walk_state      - Current method state
+ *              Flags           - Used for string conversion
  *
  * RETURN:      Status
  *
@@ -70,13 +70,13 @@ acpi_status
 acpi_ex_convert_to_integer (
        union acpi_operand_object       *obj_desc,
        union acpi_operand_object       **result_desc,
-       struct acpi_walk_state          *walk_state)
+       u32                             flags)
 {
-       u32                             i;
-       union acpi_operand_object       *ret_desc;
-       u32                             count;
+       union acpi_operand_object       *return_desc;
        u8                              *pointer;
        acpi_integer                    result;
+       u32                             i;
+       u32                             count;
        acpi_status                     status;
 
 
@@ -85,15 +85,17 @@ acpi_ex_convert_to_integer (
 
        switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
        case ACPI_TYPE_INTEGER:
+
+               /* No conversion necessary */
+
                *result_desc = obj_desc;
                return_ACPI_STATUS (AE_OK);
 
+       case ACPI_TYPE_BUFFER:
        case ACPI_TYPE_STRING:
-               pointer = (u8 *) obj_desc->string.pointer;
-               count   = obj_desc->string.length;
-               break;
 
-       case ACPI_TYPE_BUFFER:
+               /* Note: Takes advantage of common buffer/string fields */
+
                pointer = obj_desc->buffer.pointer;
                count   = obj_desc->buffer.length;
                break;
@@ -126,10 +128,12 @@ acpi_ex_convert_to_integer (
        case ACPI_TYPE_STRING:
 
                /*
-                * Convert string to an integer
-                * String must be hexadecimal as per the ACPI specification
+                * Convert string to an integer - for most cases, the string must be
+                * hexadecimal as per the ACPI specification.  The only exception (as
+                * of ACPI 3.0) is that the to_integer() operator allows both decimal
+                * and hexadecimal strings (hex prefixed with "0x").
                 */
-               status = acpi_ut_strtoul64 ((char *) pointer, 16, &result);
+               status = acpi_ut_strtoul64 ((char *) pointer, flags, &result);
                if (ACPI_FAILURE (status)) {
                        return_ACPI_STATUS (status);
                }
@@ -139,8 +143,8 @@ acpi_ex_convert_to_integer (
        case ACPI_TYPE_BUFFER:
 
                /*
-                * Buffer conversion - we simply grab enough raw data from the
-                * buffer to fill an integer
+                * Convert buffer to an integer - we simply grab enough raw data
+                * from the buffer to fill an integer
                 */
                for (i = 0; i < count; i++) {
                        /*
@@ -161,27 +165,15 @@ acpi_ex_convert_to_integer (
        /*
         * Create a new integer
         */
-       ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
-       if (!ret_desc) {
+       return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+       if (!return_desc) {
                return_ACPI_STATUS (AE_NO_MEMORY);
        }
 
        /* Save the Result */
 
-       ret_desc->integer.value = result;
-
-       /*
-        * If we are about to overwrite the original object on the operand stack,
-        * we must remove a reference on the original object because we are
-        * essentially removing it from the stack.
-        */
-       if (*result_desc == obj_desc) {
-               if (walk_state->opcode != AML_STORE_OP) {
-                       acpi_ut_remove_reference (obj_desc);
-               }
-       }
-
-       *result_desc = ret_desc;
+       return_desc->integer.value = result;
+       *result_desc = return_desc;
        return_ACPI_STATUS (AE_OK);
 }
 
@@ -193,7 +185,6 @@ acpi_ex_convert_to_integer (
  * PARAMETERS:  obj_desc        - Object to be converted.  Must be an
  *                                Integer, Buffer, or String
  *              result_desc     - Where the new buffer object is returned
- *              walk_state      - Current method state
  *
  * RETURN:      Status
  *
@@ -204,11 +195,9 @@ acpi_ex_convert_to_integer (
 acpi_status
 acpi_ex_convert_to_buffer (
        union acpi_operand_object       *obj_desc,
-       union acpi_operand_object       **result_desc,
-       struct acpi_walk_state          *walk_state)
+       union acpi_operand_object       **result_desc)
 {
-       union acpi_operand_object       *ret_desc;
-       u32                             i;
+       union acpi_operand_object       *return_desc;
        u8                              *new_buf;
 
 
@@ -230,17 +219,17 @@ acpi_ex_convert_to_buffer (
                 * Create a new Buffer object.
                 * Need enough space for one integer
                 */
-               ret_desc = acpi_ut_create_buffer_object (acpi_gbl_integer_byte_width);
-               if (!ret_desc) {
+               return_desc = acpi_ut_create_buffer_object (acpi_gbl_integer_byte_width);
+               if (!return_desc) {
                        return_ACPI_STATUS (AE_NO_MEMORY);
                }
 
-               /* Copy the integer to the buffer */
+               /* Copy the integer to the buffer, LSB first */
 
-               new_buf = ret_desc->buffer.pointer;
-               for (i = 0; i < acpi_gbl_integer_byte_width; i++) {
-                       new_buf[i] = (u8) (obj_desc->integer.value >> (i * 8));
-               }
+               new_buf = return_desc->buffer.pointer;
+               ACPI_MEMCPY (new_buf,
+                                 &obj_desc->integer.value,
+                                 acpi_gbl_integer_byte_width);
                break;
 
 
@@ -250,14 +239,14 @@ acpi_ex_convert_to_buffer (
                 * Create a new Buffer object
                 * Size will be the string length
                 */
-               ret_desc = acpi_ut_create_buffer_object ((acpi_size) obj_desc->string.length);
-               if (!ret_desc) {
+               return_desc = acpi_ut_create_buffer_object ((acpi_size) obj_desc->string.length);
+               if (!return_desc) {
                        return_ACPI_STATUS (AE_NO_MEMORY);
                }
 
                /* Copy the string to the buffer */
 
-               new_buf = ret_desc->buffer.pointer;
+               new_buf = return_desc->buffer.pointer;
                ACPI_STRNCPY ((char *) new_buf, (char *) obj_desc->string.pointer,
                        obj_desc->string.length);
                break;
@@ -269,32 +258,20 @@ acpi_ex_convert_to_buffer (
 
        /* Mark buffer initialized */
 
-       ret_desc->common.flags |= AOPOBJ_DATA_VALID;
-
-       /*
-        * If we are about to overwrite the original object on the operand stack,
-        * we must remove a reference on the original object because we are
-        * essentially removing it from the stack.
-        */
-       if (*result_desc == obj_desc) {
-               if (walk_state->opcode != AML_STORE_OP) {
-                       acpi_ut_remove_reference (obj_desc);
-               }
-       }
-
-       *result_desc = ret_desc;
+       return_desc->common.flags |= AOPOBJ_DATA_VALID;
+       *result_desc = return_desc;
        return_ACPI_STATUS (AE_OK);
 }
 
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ex_convert_ascii
+ * FUNCTION:    acpi_ex_convert_to_ascii
  *
  * PARAMETERS:  Integer         - Value to be converted
- *              Base            - 10 or 16
+ *              Base            - ACPI_STRING_DECIMAL or ACPI_STRING_HEX
  *              String          - Where the string is returned
- *              data_width      - Size of data item to be converted
+ *              data_width      - Size of data item to be converted, in bytes
  *
  * RETURN:      Actual string length
  *
@@ -305,79 +282,81 @@ acpi_ex_convert_to_buffer (
 u32
 acpi_ex_convert_to_ascii (
        acpi_integer                    integer,
-       u32                             base,
+       u16                             base,
        u8                              *string,
        u8                              data_width)
 {
-       u32                             i;
-       u32                             j;
-       u32                             k = 0;
-       char                            hex_digit;
        acpi_integer                    digit;
+       acpi_native_uint                i;
+       acpi_native_uint                j;
+       acpi_native_uint                k = 0;
+       acpi_native_uint                hex_length;
+       acpi_native_uint                decimal_length;
        u32                             remainder;
-       u32                             length;
-       u8                              leading_zero;
+       u8                              supress_zeros;
 
 
        ACPI_FUNCTION_ENTRY ();
 
 
-       if (data_width < sizeof (acpi_integer)) {
-               leading_zero = FALSE;
-               length = data_width;
-       }
-       else {
-               leading_zero = TRUE;
-               length = sizeof (acpi_integer);
-       }
-
        switch (base) {
        case 10:
 
+               /* Setup max length for the decimal number */
+
+               switch (data_width) {
+               case 1:
+                       decimal_length = ACPI_MAX8_DECIMAL_DIGITS;
+                       break;
+
+               case 4:
+                       decimal_length = ACPI_MAX32_DECIMAL_DIGITS;
+                       break;
+
+               case 8:
+               default:
+                       decimal_length = ACPI_MAX64_DECIMAL_DIGITS;
+                       break;
+               }
+
+               supress_zeros = TRUE;    /* No leading zeros */
                remainder = 0;
-               for (i = ACPI_MAX_DECIMAL_DIGITS; i > 0; i--) {
+
+               for (i = decimal_length; i > 0; i--) {
                        /* Divide by nth factor of 10 */
 
                        digit = integer;
                        for (j = 0; j < i; j++) {
-                               (void) acpi_ut_short_divide (&digit, 10, &digit, &remainder);
+                               (void) acpi_ut_short_divide (digit, 10, &digit, &remainder);
                        }
 
-                       /* Create the decimal digit */
+                       /* Handle leading zeros */
 
                        if (remainder != 0) {
-                               leading_zero = FALSE;
+                               supress_zeros = FALSE;
                        }
 
-                       if (!leading_zero) {
+                       if (!supress_zeros) {
                                string[k] = (u8) (ACPI_ASCII_ZERO + remainder);
                                k++;
                        }
                }
                break;
 
-
        case 16:
 
-               /* Copy the integer to the buffer */
+               hex_length = ACPI_MUL_2 (data_width); /* 2 ascii hex chars per data byte */
 
-               for (i = 0, j = ((length * 2) -1); i < (length * 2); i++, j--) {
+               for (i = 0, j = (hex_length-1); i < hex_length; i++, j--) {
+                       /* Get one hex digit, most significant digits first */
 
-                       hex_digit = acpi_ut_hex_to_ascii_char (integer, (j * 4));
-                       if (hex_digit != ACPI_ASCII_ZERO) {
-                               leading_zero = FALSE;
-                       }
-
-                       if (!leading_zero) {
-                               string[k] = (u8) hex_digit;
-                               k++;
-                       }
+                       string[k] = (u8) acpi_ut_hex_to_ascii_char (integer, ACPI_MUL_4 (j));
+                       k++;
                }
                break;
 
-
        default:
-               break;
+               return (0);
        }
 
        /*
@@ -392,7 +371,7 @@ acpi_ex_convert_to_ascii (
        }
 
        string [k] = 0;
-       return (k);
+       return ((u32) k);
 }
 
 
@@ -401,11 +380,9 @@ acpi_ex_convert_to_ascii (
  * FUNCTION:    acpi_ex_convert_to_string
  *
  * PARAMETERS:  obj_desc        - Object to be converted.  Must be an
- *                                  Integer, Buffer, or String
+ *                                Integer, Buffer, or String
  *              result_desc     - Where the string object is returned
- *              Base            - 10 or 16
- *              max_length      - Max length of the returned string
- *              walk_state      - Current method state
+ *              Type            - String flags (base and conversion type)
  *
  * RETURN:      Status
  *
@@ -417,15 +394,14 @@ acpi_status
 acpi_ex_convert_to_string (
        union acpi_operand_object       *obj_desc,
        union acpi_operand_object       **result_desc,
-       u32                             base,
-       u32                             max_length,
-       struct acpi_walk_state          *walk_state)
+       u32                             type)
 {
-       union acpi_operand_object       *ret_desc;
+       union acpi_operand_object       *return_desc;
        u8                              *new_buf;
-       u8                              *pointer;
-       u32                             string_length;
+       u32                             string_length = 0;
+       u16                             base = 16;
        u32                             i;
+       u8                              separator = ',';
 
 
        ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_string", obj_desc);
@@ -434,130 +410,129 @@ acpi_ex_convert_to_string (
        switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
        case ACPI_TYPE_STRING:
 
-               if (max_length >= obj_desc->string.length) {
-                       *result_desc = obj_desc;
-                       return_ACPI_STATUS (AE_OK);
-               }
-               else {
-                       /* Must copy the string first and then truncate it */
+               /* No conversion necessary */
 
-                       return_ACPI_STATUS (AE_NOT_IMPLEMENTED);
-               }
+               *result_desc = obj_desc;
+               return_ACPI_STATUS (AE_OK);
 
 
        case ACPI_TYPE_INTEGER:
 
-               string_length = acpi_gbl_integer_byte_width * 2;
-               if (base == 10) {
+               switch (type) {
+               case ACPI_EXPLICIT_CONVERT_DECIMAL:
+
+                       /* Make room for maximum decimal number */
+
                        string_length = ACPI_MAX_DECIMAL_DIGITS;
+                       base = 10;
+                       break;
+
+               default:
+
+                       /* Two hex string characters for each integer byte */
+
+                       string_length = ACPI_MUL_2 (acpi_gbl_integer_byte_width);
+                       break;
                }
 
                /*
                 * Create a new String
+                * Need enough space for one ASCII integer (plus null terminator)
                 */
-               ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
-               if (!ret_desc) {
+               return_desc = acpi_ut_create_string_object ((acpi_size) string_length);
+               if (!return_desc) {
                        return_ACPI_STATUS (AE_NO_MEMORY);
                }
 
-               /* Need enough space for one ASCII integer plus null terminator */
+               new_buf = return_desc->buffer.pointer;
 
-               new_buf = ACPI_MEM_CALLOCATE ((acpi_size) string_length + 1);
-               if (!new_buf) {
-                       ACPI_REPORT_ERROR
-                               (("ex_convert_to_string: Buffer allocation failure\n"));
-                       acpi_ut_remove_reference (ret_desc);
-                       return_ACPI_STATUS (AE_NO_MEMORY);
-               }
+               /* Convert integer to string */
 
-               /* Convert */
-
-               i = acpi_ex_convert_to_ascii (obj_desc->integer.value, base, new_buf, sizeof (acpi_integer));
+               string_length = acpi_ex_convert_to_ascii (obj_desc->integer.value, base,
+                                  new_buf, acpi_gbl_integer_byte_width);
 
                /* Null terminate at the correct place */
 
-               if (max_length < i) {
-                       new_buf[max_length] = 0;
-                       ret_desc->string.length = max_length;
-               }
-               else {
-                       new_buf [i] = 0;
-                       ret_desc->string.length = i;
-               }
-
-               ret_desc->buffer.pointer = new_buf;
+               return_desc->string.length = string_length;
+               new_buf [string_length] = 0;
                break;
 
 
        case ACPI_TYPE_BUFFER:
 
-               /* Find the string length */
+               switch (type) {
+               case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string operator */
+                       /*
+                        * From ACPI: "If Data is a buffer, it is converted to a string of
+                        * decimal values separated by commas."
+                        */
+                       base = 10;
+                       string_length = obj_desc->buffer.length; /* 4 chars for each decimal */
 
-               pointer = obj_desc->buffer.pointer;
-               for (string_length = 0; string_length < obj_desc->buffer.length; string_length++) {
-                       /* Exit on null terminator */
+                       /*lint -fallthrough */
 
-                       if (!pointer[string_length]) {
-                               break;
+               case ACPI_IMPLICIT_CONVERT_HEX:
+                       /*
+                        * From the ACPI spec:
+                        *"The entire contents of the buffer are converted to a string of
+                        * two-character hexadecimal numbers, each separated by a space."
+                        */
+                       if (type == ACPI_IMPLICIT_CONVERT_HEX) {
+                               separator = ' ';
                        }
-               }
 
-               if (max_length > ACPI_MAX_STRING_CONVERSION) {
-                       if (string_length > ACPI_MAX_STRING_CONVERSION) {
+                       /*lint -fallthrough */
+
+               case ACPI_EXPLICIT_CONVERT_HEX:     /* Used by to_hex_string operator */
+                       /*
+                        * From ACPI: "If Data is a buffer, it is converted to a string of
+                        * hexadecimal values separated by commas."
+                        */
+                       string_length += (obj_desc->buffer.length * 3);
+                       if (string_length > ACPI_MAX_STRING_CONVERSION) /* ACPI limit */ {
                                return_ACPI_STATUS (AE_AML_STRING_LIMIT);
                        }
-               }
 
-               /*
-                * Create a new string object
-                */
-               ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
-               if (!ret_desc) {
-                       return_ACPI_STATUS (AE_NO_MEMORY);
-               }
+                       /* Create a new string object and string buffer */
 
-               /* String length is the lesser of the Max or the actual length */
+                       return_desc = acpi_ut_create_string_object ((acpi_size) string_length -1);
+                       if (!return_desc) {
+                               return_ACPI_STATUS (AE_NO_MEMORY);
+                       }
 
-               if (max_length < string_length) {
-                       string_length = max_length;
-               }
+                       new_buf = return_desc->buffer.pointer;
 
-               new_buf = ACPI_MEM_CALLOCATE ((acpi_size) string_length + 1);
-               if (!new_buf) {
-                       ACPI_REPORT_ERROR
-                               (("ex_convert_to_string: Buffer allocation failure\n"));
-                       acpi_ut_remove_reference (ret_desc);
-                       return_ACPI_STATUS (AE_NO_MEMORY);
-               }
+                       /*
+                        * Convert buffer bytes to hex or decimal values
+                        * (separated by commas)
+                        */
+                       for (i = 0; i < obj_desc->buffer.length; i++) {
+                               new_buf += acpi_ex_convert_to_ascii (
+                                                (acpi_integer) obj_desc->buffer.pointer[i], base,
+                                                new_buf, 1);
+                               *new_buf++ = separator; /* each separated by a comma or space */
+                       }
 
-               /* Copy the appropriate number of buffer characters */
+                       /* Null terminate the string (overwrites final comma from above) */
 
-               ACPI_MEMCPY (new_buf, pointer, string_length);
+                       new_buf--;
+                       *new_buf = 0;
 
-               /* Null terminate */
+                       /* Recalculate length */
 
-               new_buf [string_length] = 0;
-               ret_desc->buffer.pointer = new_buf;
-               ret_desc->string.length = string_length;
-               break;
+                       return_desc->string.length = ACPI_STRLEN (return_desc->string.pointer);
+                       break;
 
+               default:
+                       return_ACPI_STATUS (AE_BAD_PARAMETER);
+               }
+               break;
 
        default:
                return_ACPI_STATUS (AE_TYPE);
        }
 
-       /*
-        * If we are about to overwrite the original object on the operand stack,
-        * we must remove a reference on the original object because we are
-        * essentially removing it from the stack.
-        */
-       if (*result_desc == obj_desc) {
-               if (walk_state->opcode != AML_STORE_OP) {
-                       acpi_ut_remove_reference (obj_desc);
-               }
-       }
-
-       *result_desc = ret_desc;
+       *result_desc = return_desc;
        return_ACPI_STATUS (AE_OK);
 }
 
@@ -635,7 +610,8 @@ acpi_ex_convert_to_target_type (
                         * These types require an Integer operand.  We can convert
                         * a Buffer or a String to an Integer if necessary.
                         */
-                       status = acpi_ex_convert_to_integer (source_desc, result_desc, walk_state);
+                       status = acpi_ex_convert_to_integer (source_desc, result_desc,
+                                        16);
                        break;
 
 
@@ -645,7 +621,8 @@ acpi_ex_convert_to_target_type (
                         * The operand must be a String.  We can convert an
                         * Integer or Buffer if necessary
                         */
-                       status = acpi_ex_convert_to_string (source_desc, result_desc, 16, ACPI_UINT32_MAX, walk_state);
+                       status = acpi_ex_convert_to_string (source_desc, result_desc,
+                                        ACPI_IMPLICIT_CONVERT_HEX);
                        break;
 
 
@@ -655,7 +632,7 @@ acpi_ex_convert_to_target_type (
                         * The operand must be a Buffer.  We can convert an
                         * Integer or String if necessary
                         */
-                       status = acpi_ex_convert_to_buffer (source_desc, result_desc, walk_state);
+                       status = acpi_ex_convert_to_buffer (source_desc, result_desc);
                        break;
 
 
index 5c2c912..042f0c9 100644 (file)
@@ -55,7 +55,6 @@
 /*
  * The following routines are used for debug output only
  */
-
 #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
 /*****************************************************************************
@@ -64,7 +63,7 @@
  *
  * PARAMETERS:  *obj_desc         - Pointer to entry to be dumped
  *
- * RETURN:      Status
+ * RETURN:      None
  *
  * DESCRIPTION: Dump an operand object
  *
 
 void
 acpi_ex_dump_operand (
-       union acpi_operand_object       *obj_desc)
+       union acpi_operand_object       *obj_desc,
+       u32                             depth)
 {
-       u8                              *buf = NULL;
        u32                             length;
-       union acpi_operand_object       **element;
-       u16                             element_index;
+       u32                             index;
 
 
        ACPI_FUNCTION_NAME ("ex_dump_operand")
@@ -89,9 +87,9 @@ acpi_ex_dump_operand (
 
        if (!obj_desc) {
                /*
-                * This usually indicates that something serious is wrong
+                * This could be a null element of a package
                 */
-               acpi_os_printf ("Null Object Descriptor\n");
+               ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Null Object Descriptor\n"));
                return;
        }
 
@@ -103,15 +101,19 @@ acpi_ex_dump_operand (
 
        if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
                ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
-                               "%p is not a node or operand object: [%s]\n",
-                               obj_desc, acpi_ut_get_descriptor_name (obj_desc)));
+                       "%p is not a node or operand object: [%s]\n",
+                       obj_desc, acpi_ut_get_descriptor_name (obj_desc)));
                ACPI_DUMP_BUFFER (obj_desc, sizeof (union acpi_operand_object));
                return;
        }
 
        /* obj_desc is a valid object */
 
-       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc));
+       if (depth > 0) {
+               ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "%*s[%u] ", depth, " ", depth));
+       }
+       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "%p ", obj_desc));
+
 
        switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
        case ACPI_TYPE_LOCAL_REFERENCE:
@@ -125,8 +127,8 @@ acpi_ex_dump_operand (
 
                case AML_NAME_OP:
 
-                       ACPI_DUMP_PATHNAME (obj_desc->reference.object, "Reference: Name: ",
-                                         ACPI_LV_INFO, _COMPONENT);
+                       ACPI_DUMP_PATHNAME (obj_desc->reference.object,
+                               "Reference: Name: ", ACPI_LV_INFO, _COMPONENT);
                        ACPI_DUMP_ENTRY (obj_desc->reference.object, ACPI_LV_INFO);
                        break;
 
@@ -134,27 +136,27 @@ acpi_ex_dump_operand (
                case AML_INDEX_OP:
 
                        acpi_os_printf ("Reference: Index %p\n",
-                                        obj_desc->reference.object);
+                               obj_desc->reference.object);
                        break;
 
 
                case AML_REF_OF_OP:
 
                        acpi_os_printf ("Reference: (ref_of) %p\n",
-                                        obj_desc->reference.object);
+                               obj_desc->reference.object);
                        break;
 
 
                case AML_ARG_OP:
 
                        acpi_os_printf ("Reference: Arg%d",
-                                        obj_desc->reference.offset);
+                               obj_desc->reference.offset);
 
                        if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
                                /* Value is an Integer */
 
                                acpi_os_printf (" value is [%8.8X%8.8x]",
-                                                ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+                                       ACPI_FORMAT_UINT64 (obj_desc->integer.value));
                        }
 
                        acpi_os_printf ("\n");
@@ -164,14 +166,14 @@ acpi_ex_dump_operand (
                case AML_LOCAL_OP:
 
                        acpi_os_printf ("Reference: Local%d",
-                                        obj_desc->reference.offset);
+                               obj_desc->reference.offset);
 
                        if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
 
                                /* Value is an Integer */
 
                                acpi_os_printf (" value is [%8.8X%8.8x]",
-                                                ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+                                       ACPI_FORMAT_UINT64 (obj_desc->integer.value));
                        }
 
                        acpi_os_printf ("\n");
@@ -181,7 +183,7 @@ acpi_ex_dump_operand (
                case AML_INT_NAMEPATH_OP:
 
                        acpi_os_printf ("Reference.Node->Name %X\n",
-                                        obj_desc->reference.node->name.integer);
+                               obj_desc->reference.node->name.integer);
                        break;
 
 
@@ -194,18 +196,15 @@ acpi_ex_dump_operand (
                        break;
 
                }
-
                break;
 
 
        case ACPI_TYPE_BUFFER:
 
                acpi_os_printf ("Buffer len %X @ %p \n",
-                                obj_desc->buffer.length,
-                                obj_desc->buffer.pointer);
+                       obj_desc->buffer.length, obj_desc->buffer.pointer);
 
                length = obj_desc->buffer.length;
-
                if (length > 64) {
                        length = 64;
                }
@@ -215,41 +214,37 @@ acpi_ex_dump_operand (
                if (obj_desc->buffer.pointer) {
                        acpi_os_printf ("Buffer Contents: ");
 
-                       for (buf = obj_desc->buffer.pointer; length--; ++buf) {
-                               acpi_os_printf (" %02x", *buf);
+                       for (index = 0; index < length; index++) {
+                               acpi_os_printf (" %02x", obj_desc->buffer.pointer[index]);
                        }
                        acpi_os_printf ("\n");
                }
-
                break;
 
 
        case ACPI_TYPE_INTEGER:
 
                acpi_os_printf ("Integer %8.8X%8.8X\n",
-                                ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+                       ACPI_FORMAT_UINT64 (obj_desc->integer.value));
                break;
 
 
        case ACPI_TYPE_PACKAGE:
 
-               acpi_os_printf ("Package count %X @ %p\n",
-                                obj_desc->package.count, obj_desc->package.elements);
+               acpi_os_printf ("Package [Len %X] element_array %p\n",
+                       obj_desc->package.count, obj_desc->package.elements);
 
                /*
-                * If elements exist, package vector pointer is valid,
+                * If elements exist, package element pointer is valid,
                 * and debug_level exceeds 1, dump package's elements.
                 */
                if (obj_desc->package.count &&
                        obj_desc->package.elements &&
                        acpi_dbg_level > 1) {
-                       for (element_index = 0, element = obj_desc->package.elements;
-                                 element_index < obj_desc->package.count;
-                                 ++element_index, ++element) {
-                               acpi_ex_dump_operand (*element);
+                       for (index = 0; index < obj_desc->package.count; index++) {
+                               acpi_ex_dump_operand (obj_desc->package.elements[index], depth+1);
                        }
                }
-               acpi_os_printf ("\n");
                break;
 
 
@@ -277,7 +272,7 @@ acpi_ex_dump_operand (
        case ACPI_TYPE_STRING:
 
                acpi_os_printf ("String length %X @ %p ",
-                                obj_desc->string.length, obj_desc->string.pointer);
+                       obj_desc->string.length, obj_desc->string.pointer);
                acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX);
                acpi_os_printf ("\n");
                break;
@@ -297,7 +292,7 @@ acpi_ex_dump_operand (
                        obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK,
                        obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK,
                        obj_desc->field.base_byte_offset, obj_desc->field.start_field_bit_offset);
-               ACPI_DUMP_STACK_ENTRY (obj_desc->field.region_obj);
+               acpi_ex_dump_operand (obj_desc->field.region_obj, depth+1);
                break;
 
 
@@ -321,9 +316,8 @@ acpi_ex_dump_operand (
                        acpi_os_printf ("*not a Buffer* \n");
                }
                else {
-                       ACPI_DUMP_STACK_ENTRY (obj_desc->buffer_field.buffer_obj);
+                       acpi_ex_dump_operand (obj_desc->buffer_field.buffer_obj, depth+1);
                }
-
                break;
 
 
@@ -387,10 +381,13 @@ acpi_ex_dump_operand (
  *
  * FUNCTION:    acpi_ex_dump_operands
  *
- * PARAMETERS:  interpreter_mode     - Load or Exec
- *              *Ident              - Identification
+ * PARAMETERS:  Operands            - Operand list
+ *              interpreter_mode    - Load or Exec
+ *              Ident               - Identification
  *              num_levels          - # of stack entries to dump above line
- *              *Note               - Output notation
+ *              Note                - Output notation
+ *              module_name         - Caller's module name
+ *              line_number         - Caller's invocation line number
  *
  * DESCRIPTION: Dump the object stack
  *
@@ -407,7 +404,6 @@ acpi_ex_dump_operands (
        u32                             line_number)
 {
        acpi_native_uint                i;
-       union acpi_operand_object       **obj_desc;
 
 
        ACPI_FUNCTION_NAME ("ex_dump_operands");
@@ -432,8 +428,7 @@ acpi_ex_dump_operands (
        /* Dump the operand stack starting at the top */
 
        for (i = 0; num_levels > 0; i--, num_levels--) {
-               obj_desc = &operands[i];
-               acpi_ex_dump_operand (*obj_desc);
+               acpi_ex_dump_operand (operands[i], 0);
        }
 
        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
@@ -443,6 +438,8 @@ acpi_ex_dump_operands (
 }
 
 
+#ifdef ACPI_FUTURE_USAGE
+
 /*****************************************************************************
  *
  * FUNCTION:    acpi_ex_out*
@@ -489,8 +486,7 @@ acpi_ex_out_address (
 #if ACPI_MACHINE_WIDTH == 16
        acpi_os_printf ("%20s : %p\n", title, value);
 #else
-       acpi_os_printf ("%20s : %8.8X%8.8X\n", title,
-                        ACPI_FORMAT_UINT64 (value));
+       acpi_os_printf ("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64 (value));
 #endif
 }
 
@@ -499,7 +495,7 @@ acpi_ex_out_address (
  *
  * FUNCTION:    acpi_ex_dump_node
  *
- * PARAMETERS:  *Node           - Descriptor to dump
+ * PARAMETERS:  *Node               - Descriptor to dump
  *              Flags               - Force display
  *
  * DESCRIPTION: Dumps the members of the given.Node
@@ -563,22 +559,25 @@ acpi_ex_dump_object_descriptor (
 
        if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) {
                acpi_ex_dump_node ((struct acpi_namespace_node *) obj_desc, flags);
-               acpi_os_printf ("\nAttached Object (%p):\n", ((struct acpi_namespace_node *) obj_desc)->object);
-               acpi_ex_dump_object_descriptor (((struct acpi_namespace_node *) obj_desc)->object, flags);
-               return;
+               acpi_os_printf ("\nAttached Object (%p):\n",
+                       ((struct acpi_namespace_node *) obj_desc)->object);
+               acpi_ex_dump_object_descriptor (
+                       ((struct acpi_namespace_node *) obj_desc)->object, flags);
+               return_VOID;
        }
 
        if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
-               acpi_os_printf ("ex_dump_object_descriptor: %p is not an ACPI operand object: [%s]\n",
-                               obj_desc, acpi_ut_get_descriptor_name (obj_desc));
+               acpi_os_printf (
+                       "ex_dump_object_descriptor: %p is not an ACPI operand object: [%s]\n",
+                       obj_desc, acpi_ut_get_descriptor_name (obj_desc));
                return_VOID;
        }
 
        /* Common Fields */
 
-       acpi_ex_out_string ("Type",          acpi_ut_get_object_type_name (obj_desc));
+       acpi_ex_out_string ("Type",             acpi_ut_get_object_type_name (obj_desc));
        acpi_ex_out_integer ("Reference Count", obj_desc->common.reference_count);
-       acpi_ex_out_integer ("Flags",        obj_desc->common.flags);
+       acpi_ex_out_integer ("Flags",           obj_desc->common.flags);
 
        /* Object-specific Fields */
 
@@ -592,7 +591,7 @@ acpi_ex_dump_object_descriptor (
 
        case ACPI_TYPE_STRING:
 
-               acpi_ex_out_integer ("Length",       obj_desc->string.length);
+               acpi_ex_out_integer ("Length",      obj_desc->string.length);
 
                acpi_os_printf ("%20s : %p ", "Pointer", obj_desc->string.pointer);
                acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX);
@@ -602,17 +601,17 @@ acpi_ex_dump_object_descriptor (
 
        case ACPI_TYPE_BUFFER:
 
-               acpi_ex_out_integer ("Length",       obj_desc->buffer.length);
-               acpi_ex_out_pointer ("Pointer",      obj_desc->buffer.pointer);
+               acpi_ex_out_integer ("Length",      obj_desc->buffer.length);
+               acpi_ex_out_pointer ("Pointer",     obj_desc->buffer.pointer);
                ACPI_DUMP_BUFFER (obj_desc->buffer.pointer, obj_desc->buffer.length);
                break;
 
 
        case ACPI_TYPE_PACKAGE:
 
-               acpi_ex_out_integer ("Flags",        obj_desc->package.flags);
-               acpi_ex_out_integer ("Count",        obj_desc->package.count);
-               acpi_ex_out_pointer ("Elements",     obj_desc->package.elements);
+               acpi_ex_out_integer ("Flags",       obj_desc->package.flags);
+               acpi_ex_out_integer ("Count",       obj_desc->package.count);
+               acpi_ex_out_pointer ("Elements",    obj_desc->package.elements);
 
                /* Dump the package contents */
 
@@ -621,7 +620,8 @@ acpi_ex_dump_object_descriptor (
                        for (i = 0; i < obj_desc->package.count; i++) {
                                acpi_os_printf ("[%.3d] %p", i, obj_desc->package.elements[i]);
                                if (obj_desc->package.elements[i]) {
-                                       acpi_os_printf (" %s", acpi_ut_get_object_type_name (obj_desc->package.elements[i]));
+                                       acpi_os_printf (" %s",
+                                               acpi_ut_get_object_type_name (obj_desc->package.elements[i]));
                                }
                                acpi_os_printf ("\n");
                        }
@@ -639,38 +639,38 @@ acpi_ex_dump_object_descriptor (
 
        case ACPI_TYPE_EVENT:
 
-               acpi_ex_out_pointer ("Semaphore",    obj_desc->event.semaphore);
+               acpi_ex_out_pointer ("Semaphore",   obj_desc->event.semaphore);
                break;
 
 
        case ACPI_TYPE_METHOD:
 
-               acpi_ex_out_integer ("param_count",  obj_desc->method.param_count);
-               acpi_ex_out_integer ("Concurrency",  obj_desc->method.concurrency);
-               acpi_ex_out_pointer ("Semaphore",    obj_desc->method.semaphore);
-               acpi_ex_out_integer ("owning_id",    obj_desc->method.owning_id);
-               acpi_ex_out_integer ("aml_length",   obj_desc->method.aml_length);
-               acpi_ex_out_pointer ("aml_start",    obj_desc->method.aml_start);
+               acpi_ex_out_integer ("param_count", obj_desc->method.param_count);
+               acpi_ex_out_integer ("Concurrency", obj_desc->method.concurrency);
+               acpi_ex_out_pointer ("Semaphore",   obj_desc->method.semaphore);
+               acpi_ex_out_integer ("owning_id",   obj_desc->method.owning_id);
+               acpi_ex_out_integer ("aml_length",  obj_desc->method.aml_length);
+               acpi_ex_out_pointer ("aml_start",   obj_desc->method.aml_start);
                break;
 
 
        case ACPI_TYPE_MUTEX:
 
-               acpi_ex_out_integer ("sync_level",   obj_desc->mutex.sync_level);
+               acpi_ex_out_integer ("sync_level",  obj_desc->mutex.sync_level);
                acpi_ex_out_pointer ("owner_thread", obj_desc->mutex.owner_thread);
-               acpi_ex_out_integer ("acquisition_depth",obj_desc->mutex.acquisition_depth);
-               acpi_ex_out_pointer ("Semaphore",    obj_desc->mutex.semaphore);
+               acpi_ex_out_integer ("acquire_depth", obj_desc->mutex.acquisition_depth);
+               acpi_ex_out_pointer ("Semaphore",   obj_desc->mutex.semaphore);
                break;
 
 
        case ACPI_TYPE_REGION:
 
-               acpi_ex_out_integer ("space_id",     obj_desc->region.space_id);
-               acpi_ex_out_integer ("Flags",        obj_desc->region.flags);
-               acpi_ex_out_address ("Address",      obj_desc->region.address);
-               acpi_ex_out_integer ("Length",       obj_desc->region.length);
-               acpi_ex_out_pointer ("Handler",      obj_desc->region.handler);
-               acpi_ex_out_pointer ("Next",         obj_desc->region.next);
+               acpi_ex_out_integer ("space_id",    obj_desc->region.space_id);
+               acpi_ex_out_integer ("Flags",       obj_desc->region.flags);
+               acpi_ex_out_address ("Address",     obj_desc->region.address);
+               acpi_ex_out_integer ("Length",      obj_desc->region.length);
+               acpi_ex_out_pointer ("Handler",     obj_desc->region.handler);
+               acpi_ex_out_pointer ("Next",        obj_desc->region.next);
                break;
 
 
@@ -686,11 +686,11 @@ acpi_ex_dump_object_descriptor (
        case ACPI_TYPE_PROCESSOR:
 
                acpi_ex_out_integer ("Processor ID", obj_desc->processor.proc_id);
-               acpi_ex_out_integer ("Length",       obj_desc->processor.length);
-               acpi_ex_out_address ("Address",      (acpi_physical_address) obj_desc->processor.address);
+               acpi_ex_out_integer ("Length",      obj_desc->processor.length);
+               acpi_ex_out_address ("Address",     (acpi_physical_address) obj_desc->processor.address);
                acpi_ex_out_pointer ("system_notify", obj_desc->processor.system_notify);
                acpi_ex_out_pointer ("device_notify", obj_desc->processor.device_notify);
-               acpi_ex_out_pointer ("Handler",      obj_desc->processor.handler);
+               acpi_ex_out_pointer ("Handler",     obj_desc->processor.handler);
                break;
 
 
@@ -698,7 +698,7 @@ acpi_ex_dump_object_descriptor (
 
                acpi_ex_out_pointer ("system_notify", obj_desc->thermal_zone.system_notify);
                acpi_ex_out_pointer ("device_notify", obj_desc->thermal_zone.device_notify);
-               acpi_ex_out_pointer ("Handler",      obj_desc->thermal_zone.handler);
+               acpi_ex_out_pointer ("Handler",     obj_desc->thermal_zone.handler);
                break;
 
 
@@ -707,35 +707,35 @@ acpi_ex_dump_object_descriptor (
        case ACPI_TYPE_LOCAL_BANK_FIELD:
        case ACPI_TYPE_LOCAL_INDEX_FIELD:
 
-               acpi_ex_out_integer ("field_flags",  obj_desc->common_field.field_flags);
-               acpi_ex_out_integer ("access_byte_width", obj_desc->common_field.access_byte_width);
-               acpi_ex_out_integer ("bit_length",   obj_desc->common_field.bit_length);
+               acpi_ex_out_integer ("field_flags", obj_desc->common_field.field_flags);
+               acpi_ex_out_integer ("access_byte_width",obj_desc->common_field.access_byte_width);
+               acpi_ex_out_integer ("bit_length",  obj_desc->common_field.bit_length);
                acpi_ex_out_integer ("fld_bit_offset", obj_desc->common_field.start_field_bit_offset);
                acpi_ex_out_integer ("base_byte_offset", obj_desc->common_field.base_byte_offset);
                acpi_ex_out_integer ("datum_valid_bits", obj_desc->common_field.datum_valid_bits);
-               acpi_ex_out_integer ("end_fld_valid_bits", obj_desc->common_field.end_field_valid_bits);
-               acpi_ex_out_integer ("end_buf_valid_bits", obj_desc->common_field.end_buffer_valid_bits);
-               acpi_ex_out_pointer ("parent_node",  obj_desc->common_field.node);
+               acpi_ex_out_integer ("end_fld_valid_bits",obj_desc->common_field.end_field_valid_bits);
+               acpi_ex_out_integer ("end_buf_valid_bits",obj_desc->common_field.end_buffer_valid_bits);
+               acpi_ex_out_pointer ("parent_node", obj_desc->common_field.node);
 
                switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
                case ACPI_TYPE_BUFFER_FIELD:
-                       acpi_ex_out_pointer ("buffer_obj",   obj_desc->buffer_field.buffer_obj);
+                       acpi_ex_out_pointer ("buffer_obj", obj_desc->buffer_field.buffer_obj);
                        break;
 
                case ACPI_TYPE_LOCAL_REGION_FIELD:
-                       acpi_ex_out_pointer ("region_obj",   obj_desc->field.region_obj);
+                       acpi_ex_out_pointer ("region_obj", obj_desc->field.region_obj);
                        break;
 
                case ACPI_TYPE_LOCAL_BANK_FIELD:
-                       acpi_ex_out_integer ("Value",        obj_desc->bank_field.value);
-                       acpi_ex_out_pointer ("region_obj",   obj_desc->bank_field.region_obj);
-                       acpi_ex_out_pointer ("bank_obj",     obj_desc->bank_field.bank_obj);
+                       acpi_ex_out_integer ("Value",   obj_desc->bank_field.value);
+                       acpi_ex_out_pointer ("region_obj", obj_desc->bank_field.region_obj);
+                       acpi_ex_out_pointer ("bank_obj", obj_desc->bank_field.bank_obj);
                        break;
 
                case ACPI_TYPE_LOCAL_INDEX_FIELD:
-                       acpi_ex_out_integer ("Value",        obj_desc->index_field.value);
-                       acpi_ex_out_pointer ("Index",        obj_desc->index_field.index_obj);
-                       acpi_ex_out_pointer ("Data",         obj_desc->index_field.data_obj);
+                       acpi_ex_out_integer ("Value",   obj_desc->index_field.value);
+                       acpi_ex_out_pointer ("Index",   obj_desc->index_field.index_obj);
+                       acpi_ex_out_pointer ("Data",    obj_desc->index_field.data_obj);
                        break;
 
                default:
@@ -747,29 +747,29 @@ acpi_ex_dump_object_descriptor (
 
        case ACPI_TYPE_LOCAL_REFERENCE:
 
-               acpi_ex_out_integer ("target_type",  obj_desc->reference.target_type);
-               acpi_ex_out_string ("Opcode",        (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name);
-               acpi_ex_out_integer ("Offset",       obj_desc->reference.offset);
-               acpi_ex_out_pointer ("obj_desc",     obj_desc->reference.object);
-               acpi_ex_out_pointer ("Node",         obj_desc->reference.node);
-               acpi_ex_out_pointer ("Where",        obj_desc->reference.where);
+               acpi_ex_out_integer ("target_type", obj_desc->reference.target_type);
+               acpi_ex_out_string ("Opcode",       (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name);
+               acpi_ex_out_integer ("Offset",      obj_desc->reference.offset);
+               acpi_ex_out_pointer ("obj_desc",    obj_desc->reference.object);
+               acpi_ex_out_pointer ("Node",        obj_desc->reference.node);
+               acpi_ex_out_pointer ("Where",       obj_desc->reference.where);
                break;
 
 
        case ACPI_TYPE_LOCAL_ADDRESS_HANDLER:
 
-               acpi_ex_out_integer ("space_id",     obj_desc->address_space.space_id);
-               acpi_ex_out_pointer ("Next",         obj_desc->address_space.next);
-               acpi_ex_out_pointer ("region_list",  obj_desc->address_space.region_list);
-               acpi_ex_out_pointer ("Node",         obj_desc->address_space.node);
-               acpi_ex_out_pointer ("Context",      obj_desc->address_space.context);
+               acpi_ex_out_integer ("space_id",    obj_desc->address_space.space_id);
+               acpi_ex_out_pointer ("Next",        obj_desc->address_space.next);
+               acpi_ex_out_pointer ("region_list", obj_desc->address_space.region_list);
+               acpi_ex_out_pointer ("Node",        obj_desc->address_space.node);
+               acpi_ex_out_pointer ("Context",     obj_desc->address_space.context);
                break;
 
 
        case ACPI_TYPE_LOCAL_NOTIFY:
 
-               acpi_ex_out_pointer ("Node",         obj_desc->notify.node);
-               acpi_ex_out_pointer ("Context",      obj_desc->notify.context);
+               acpi_ex_out_pointer ("Node",        obj_desc->notify.node);
+               acpi_ex_out_pointer ("Context",     obj_desc->notify.context);
                break;
 
 
@@ -779,7 +779,8 @@ acpi_ex_dump_object_descriptor (
        case ACPI_TYPE_LOCAL_DATA:
        default:
 
-               acpi_os_printf ("ex_dump_object_descriptor: Display not implemented for object type %s\n",
+               acpi_os_printf (
+                       "ex_dump_object_descriptor: Display not implemented for object type %s\n",
                        acpi_ut_get_object_type_name (obj_desc));
                break;
        }
@@ -787,5 +788,7 @@ acpi_ex_dump_object_descriptor (
        return_VOID;
 }
 
+#endif  /*  ACPI_FUTURE_USAGE  */
+
 #endif
 
index 03ccfb9..5f8fbdb 100644 (file)
@@ -139,7 +139,7 @@ acpi_ex_setup_region (
                        if (ACPI_ROUND_UP (rgn_desc->region.length,
                                           obj_desc->common_field.access_byte_width) >=
                                (obj_desc->common_field.base_byte_offset +
-                                obj_desc->common_field.access_byte_width +
+                                (acpi_native_uint) obj_desc->common_field.access_byte_width +
                                 field_datum_byte_offset)) {
                                return_ACPI_STATUS (AE_OK);
                        }
index 961a949..6bd7934 100644 (file)
@@ -149,8 +149,9 @@ acpi_ex_get_object_reference (
  *
  * FUNCTION:    acpi_ex_concat_template
  *
- * PARAMETERS:  *obj_desc           - Object to be converted.  Must be an
- *                                    Integer, Buffer, or String
+ * PARAMETERS:  Operand0            - First source object
+ *              Operand1            - Second source object
+ *              actual_return_desc  - Where to place the return object
  *              walk_state          - Current walk state
  *
  * RETURN:      Status
@@ -161,8 +162,8 @@ acpi_ex_get_object_reference (
 
 acpi_status
 acpi_ex_concat_template (
-       union acpi_operand_object       *obj_desc1,
-       union acpi_operand_object       *obj_desc2,
+       union acpi_operand_object       *operand0,
+       union acpi_operand_object       *operand1,
        union acpi_operand_object       **actual_return_desc,
        struct acpi_walk_state          *walk_state)
 {
@@ -179,16 +180,16 @@ acpi_ex_concat_template (
 
        /* Find the end_tags in each resource template */
 
-       end_tag1 = acpi_ut_get_resource_end_tag (obj_desc1);
-       end_tag2 = acpi_ut_get_resource_end_tag (obj_desc2);
+       end_tag1 = acpi_ut_get_resource_end_tag (operand0);
+       end_tag2 = acpi_ut_get_resource_end_tag (operand1);
        if (!end_tag1 || !end_tag2) {
                return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
        }
 
        /* Compute the length of each part */
 
-       length1 = ACPI_PTR_DIFF (end_tag1, obj_desc1->buffer.pointer);
-       length2 = ACPI_PTR_DIFF (end_tag2, obj_desc2->buffer.pointer) +
+       length1 = ACPI_PTR_DIFF (end_tag1, operand0->buffer.pointer);
+       length2 = ACPI_PTR_DIFF (end_tag2, operand1->buffer.pointer) +
                          2; /* Size of END_TAG */
 
        /* Create a new buffer object for the result */
@@ -201,8 +202,8 @@ acpi_ex_concat_template (
        /* Copy the templates to the new descriptor */
 
        new_buf = return_desc->buffer.pointer;
-       ACPI_MEMCPY (new_buf, obj_desc1->buffer.pointer, length1);
-       ACPI_MEMCPY (new_buf + length1, obj_desc2->buffer.pointer, length2);
+       ACPI_MEMCPY (new_buf, operand0->buffer.pointer, length1);
+       ACPI_MEMCPY (new_buf + length1, operand1->buffer.pointer, length2);
 
        /* Compute the new checksum */
 
@@ -221,8 +222,8 @@ acpi_ex_concat_template (
  *
  * FUNCTION:    acpi_ex_do_concatenate
  *
- * PARAMETERS:  obj_desc1           - First source object
- *              obj_desc2           - Second source object
+ * PARAMETERS:  Operand0            - First source object
+ *              Operand1            - Second source object
  *              actual_return_desc  - Where to place the return object
  *              walk_state          - Current walk state
  *
@@ -234,21 +235,58 @@ acpi_ex_concat_template (
 
 acpi_status
 acpi_ex_do_concatenate (
-       union acpi_operand_object       *obj_desc1,
-       union acpi_operand_object       *obj_desc2,
+       union acpi_operand_object       *operand0,
+       union acpi_operand_object       *operand1,
        union acpi_operand_object       **actual_return_desc,
        struct acpi_walk_state          *walk_state)
 {
-       acpi_status                     status;
-       u32                             i;
-       acpi_integer                    this_integer;
+       union acpi_operand_object       *local_operand1 = operand1;
        union acpi_operand_object       *return_desc;
        char                            *new_buf;
+       acpi_status                     status;
+       acpi_size                       new_length;
 
 
-       ACPI_FUNCTION_ENTRY ();
+       ACPI_FUNCTION_TRACE ("ex_do_concatenate");
 
 
+       /*
+        * Convert the second operand if necessary.  The first operand
+        * determines the type of the second operand, (See the Data Types
+        * section of the ACPI specification.)  Both object types are
+        * guaranteed to be either Integer/String/Buffer by the operand
+        * resolution mechanism.
+        */
+       switch (ACPI_GET_OBJECT_TYPE (operand0)) {
+       case ACPI_TYPE_INTEGER:
+               status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16);
+               break;
+
+       case ACPI_TYPE_STRING:
+               status = acpi_ex_convert_to_string (operand1, &local_operand1,
+                                ACPI_IMPLICIT_CONVERT_HEX);
+               break;
+
+       case ACPI_TYPE_BUFFER:
+               status = acpi_ex_convert_to_buffer (operand1, &local_operand1);
+               break;
+
+       default:
+               ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n",
+                               ACPI_GET_OBJECT_TYPE (operand0)));
+               status = AE_AML_INTERNAL;
+       }
+
+       if (ACPI_FAILURE (status)) {
+               goto cleanup;
+       }
+
+       /*
+        * Both operands are now known to be the same object type
+        * (Both are Integer, String, or Buffer), and we can now perform the
+        * concatenation.
+        */
+
        /*
         * There are three cases to handle:
         *
@@ -256,113 +294,102 @@ acpi_ex_do_concatenate (
         * 2) Two Strings concatenated to produce a new String
         * 3) Two Buffers concatenated to produce a new Buffer
         */
-       switch (ACPI_GET_OBJECT_TYPE (obj_desc1)) {
+       switch (ACPI_GET_OBJECT_TYPE (operand0)) {
        case ACPI_TYPE_INTEGER:
 
                /* Result of two Integers is a Buffer */
                /* Need enough buffer space for two integers */
 
-               return_desc = acpi_ut_create_buffer_object (acpi_gbl_integer_byte_width * 2);
+               return_desc = acpi_ut_create_buffer_object (
+                                  ACPI_MUL_2 (acpi_gbl_integer_byte_width));
                if (!return_desc) {
-                       return (AE_NO_MEMORY);
+                       status = AE_NO_MEMORY;
+                       goto cleanup;
                }
 
                new_buf = (char *) return_desc->buffer.pointer;
 
-               /* Convert the first integer */
-
-               this_integer = obj_desc1->integer.value;
-               for (i = 0; i < acpi_gbl_integer_byte_width; i++) {
-                       new_buf[i] = (char) this_integer;
-                       this_integer >>= 8;
-               }
+               /* Copy the first integer, LSB first */
 
-               /* Convert the second integer */
+               ACPI_MEMCPY (new_buf,
+                                 &operand0->integer.value,
+                                 acpi_gbl_integer_byte_width);
 
-               this_integer = obj_desc2->integer.value;
-               for (; i < (ACPI_MUL_2 (acpi_gbl_integer_byte_width)); i++) {
-                       new_buf[i] = (char) this_integer;
-                       this_integer >>= 8;
-               }
+               /* Copy the second integer (LSB first) after the first */
 
+               ACPI_MEMCPY (new_buf + acpi_gbl_integer_byte_width,
+                                 &local_operand1->integer.value,
+                                 acpi_gbl_integer_byte_width);
                break;
 
-
        case ACPI_TYPE_STRING:
 
                /* Result of two Strings is a String */
 
-               return_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
-               if (!return_desc) {
-                       return (AE_NO_MEMORY);
+               new_length = (acpi_size) operand0->string.length +
+                                (acpi_size) local_operand1->string.length;
+               if (new_length > ACPI_MAX_STRING_CONVERSION) {
+                       status = AE_AML_STRING_LIMIT;
+                       goto cleanup;
                }
 
-               /* Operand0 is string  */
-
-               new_buf = ACPI_MEM_CALLOCATE ((acpi_size) obj_desc1->string.length +
-                                  (acpi_size) obj_desc2->string.length + 1);
-               if (!new_buf) {
-                       ACPI_REPORT_ERROR
-                               (("ex_do_concatenate: String allocation failure\n"));
+               return_desc = acpi_ut_create_string_object (new_length);
+               if (!return_desc) {
                        status = AE_NO_MEMORY;
                        goto cleanup;
                }
 
-               /* Concatenate the strings */
-
-               ACPI_STRCPY (new_buf, obj_desc1->string.pointer);
-               ACPI_STRCPY (new_buf + obj_desc1->string.length,
-                                 obj_desc2->string.pointer);
+               new_buf = return_desc->string.pointer;
 
-               /* Complete the String object initialization */
+               /* Concatenate the strings */
 
-               return_desc->string.pointer = new_buf;
-               return_desc->string.length = obj_desc1->string.length +
-                                  obj_desc2->string.length;
+               ACPI_STRCPY (new_buf,
+                                 operand0->string.pointer);
+               ACPI_STRCPY (new_buf + operand0->string.length,
+                                 local_operand1->string.pointer);
                break;
 
-
        case ACPI_TYPE_BUFFER:
 
                /* Result of two Buffers is a Buffer */
 
                return_desc = acpi_ut_create_buffer_object (
-                                  (acpi_size) obj_desc1->buffer.length +
-                                  (acpi_size) obj_desc2->buffer.length);
+                                  (acpi_size) operand0->buffer.length +
+                                  (acpi_size) local_operand1->buffer.length);
                if (!return_desc) {
-                       return (AE_NO_MEMORY);
+                       status = AE_NO_MEMORY;
+                       goto cleanup;
                }
 
                new_buf = (char *) return_desc->buffer.pointer;
 
                /* Concatenate the buffers */
 
-               ACPI_MEMCPY (new_buf, obj_desc1->buffer.pointer,
-                                 obj_desc1->buffer.length);
-               ACPI_MEMCPY (new_buf + obj_desc1->buffer.length, obj_desc2->buffer.pointer,
-                                  obj_desc2->buffer.length);
-
+               ACPI_MEMCPY (new_buf,
+                                 operand0->buffer.pointer,
+                                 operand0->buffer.length);
+               ACPI_MEMCPY (new_buf + operand0->buffer.length,
+                                 local_operand1->buffer.pointer,
+                                 local_operand1->buffer.length);
                break;
 
-
        default:
 
                /* Invalid object type, should not happen here */
 
-               ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n",
-                               ACPI_GET_OBJECT_TYPE (obj_desc1)));
-               status = AE_AML_INTERNAL;
-               return_desc = NULL;
+               ACPI_REPORT_ERROR (("Concatenate - Invalid object type: %X\n",
+                               ACPI_GET_OBJECT_TYPE (operand0)));
+               status =AE_AML_INTERNAL;
+               goto cleanup;
        }
 
        *actual_return_desc = return_desc;
-       return (AE_OK);
-
 
 cleanup:
-
-       acpi_ut_remove_reference (return_desc);
-       return (status);
+       if (local_operand1 != operand1) {
+               acpi_ut_remove_reference (local_operand1);
+       }
+       return_ACPI_STATUS (AE_OK);
 }
 
 
@@ -371,8 +398,8 @@ cleanup:
  * FUNCTION:    acpi_ex_do_math_op
  *
  * PARAMETERS:  Opcode              - AML opcode
- *              Operand0            - Integer operand #0
- *              Operand1            - Integer operand #1
+ *              Integer0            - Integer operand #0
+ *              Integer1            - Integer operand #1
  *
  * RETURN:      Integer result of the operation
  *
@@ -385,62 +412,62 @@ cleanup:
 acpi_integer
 acpi_ex_do_math_op (
        u16                             opcode,
-       acpi_integer                    operand0,
-       acpi_integer                    operand1)
+       acpi_integer                    integer0,
+       acpi_integer                    integer1)
 {
 
        ACPI_FUNCTION_ENTRY ();
 
 
        switch (opcode) {
-       case AML_ADD_OP:                /* Add (Operand0, Operand1, Result) */
+       case AML_ADD_OP:                /* Add (Integer0, Integer1, Result) */
 
-               return (operand0 + operand1);
+               return (integer0 + integer1);
 
 
-       case AML_BIT_AND_OP:            /* And (Operand0, Operand1, Result) */
+       case AML_BIT_AND_OP:            /* And (Integer0, Integer1, Result) */
 
-               return (operand0 & operand1);
+               return (integer0 & integer1);
 
 
-       case AML_BIT_NAND_OP:           /* NAnd (Operand0, Operand1, Result) */
+       case AML_BIT_NAND_OP:           /* NAnd (Integer0, Integer1, Result) */
 
-               return (~(operand0 & operand1));
+               return (~(integer0 & integer1));
 
 
-       case AML_BIT_OR_OP:             /* Or (Operand0, Operand1, Result) */
+       case AML_BIT_OR_OP:             /* Or (Integer0, Integer1, Result) */
 
-               return (operand0 | operand1);
+               return (integer0 | integer1);
 
 
-       case AML_BIT_NOR_OP:            /* NOr (Operand0, Operand1, Result) */
+       case AML_BIT_NOR_OP:            /* NOr (Integer0, Integer1, Result) */
 
-               return (~(operand0 | operand1));
+               return (~(integer0 | integer1));
 
 
-       case AML_BIT_XOR_OP:            /* XOr (Operand0, Operand1, Result) */
+       case AML_BIT_XOR_OP:            /* XOr (Integer0, Integer1, Result) */
 
-               return (operand0 ^ operand1);
+               return (integer0 ^ integer1);
 
 
-       case AML_MULTIPLY_OP:           /* Multiply (Operand0, Operand1, Result) */
+       case AML_MULTIPLY_OP:           /* Multiply (Integer0, Integer1, Result) */
 
-               return (operand0 * operand1);
+               return (integer0 * integer1);
 
 
        case AML_SHIFT_LEFT_OP:         /* shift_left (Operand, shift_count, Result) */
 
-               return (operand0 << operand1);
+               return (integer0 << integer1);
 
 
        case AML_SHIFT_RIGHT_OP:        /* shift_right (Operand, shift_count, Result) */
 
-               return (operand0 >> operand1);
+               return (integer0 >> integer1);
 
 
-       case AML_SUBTRACT_OP:           /* Subtract (Operand0, Operand1, Result) */
+       case AML_SUBTRACT_OP:           /* Subtract (Integer0, Integer1, Result) */
 
-               return (operand0 - operand1);
+               return (integer0 - integer1);
 
        default:
 
@@ -449,22 +476,86 @@ acpi_ex_do_math_op (
 }
 
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_do_logical_numeric_op
+ *
+ * PARAMETERS:  Opcode              - AML opcode
+ *              Integer0            - Integer operand #0
+ *              Integer1            - Integer operand #1
+ *              logical_result      - TRUE/FALSE result of the operation
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
+ *              operators (LAnd and LOr), both operands must be integers.
+ *
+ *              Note: cleanest machine code seems to be produced by the code
+ *              below, rather than using statements of the form:
+ *                  Result = (Integer0 && Integer1);
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_do_logical_numeric_op (
+       u16                             opcode,
+       acpi_integer                    integer0,
+       acpi_integer                    integer1,
+       u8                              *logical_result)
+{
+       acpi_status                     status = AE_OK;
+       u8                              local_result = FALSE;
+
+
+       ACPI_FUNCTION_TRACE ("ex_do_logical_numeric_op");
+
+
+       switch (opcode) {
+       case AML_LAND_OP:               /* LAnd (Integer0, Integer1) */
+
+               if (integer0 && integer1) {
+                       local_result = TRUE;
+               }
+               break;
+
+       case AML_LOR_OP:                /* LOr (Integer0, Integer1) */
+
+               if (integer0 || integer1) {
+                       local_result = TRUE;
+               }
+               break;
+
+       default:
+               status = AE_AML_INTERNAL;
+               break;
+       }
+
+       /* Return the logical result and status */
+
+       *logical_result = local_result;
+       return_ACPI_STATUS (status);
+}
+
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_do_logical_op
  *
  * PARAMETERS:  Opcode              - AML opcode
- *              obj_desc0           - operand #0
- *              obj_desc1           - operand #1
+ *              Operand0            - operand #0
+ *              Operand1            - operand #1
+ *              logical_result      - TRUE/FALSE result of the operation
  *
- * RETURN:      TRUE/FALSE result of the operation
+ * RETURN:      Status
  *
  * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
  *              functions here is to prevent a lot of pointer dereferencing
  *              to obtain the operands and to simplify the generation of the
- *              logical value.  Both operands must already be validated as
- *              1) Both the same type, and
- *              2) Either Integer, Buffer, or String type.
+ *              logical value. For the Numeric operators (LAnd and LOr), both
+ *              operands must be integers. For the other logical operators,
+ *              operands can be any combination of Integer/String/Buffer. The
+ *              first operand determines the type to which the second operand
+ *              will be converted.
  *
  *              Note: cleanest machine code seems to be produced by the code
  *              below, rather than using statements of the form:
@@ -472,143 +563,175 @@ acpi_ex_do_math_op (
  *
  ******************************************************************************/
 
-u8
+acpi_status
 acpi_ex_do_logical_op (
        u16                             opcode,
-       union acpi_operand_object       *obj_desc0,
-       union acpi_operand_object       *obj_desc1)
+       union acpi_operand_object       *operand0,
+       union acpi_operand_object       *operand1,
+       u8                              *logical_result)
 {
-       acpi_integer                    operand0;
-       acpi_integer                    operand1;
-       u8                              *ptr0;
-       u8                              *ptr1;
+       union acpi_operand_object       *local_operand1 = operand1;
+       acpi_integer                    integer0;
+       acpi_integer                    integer1;
        u32                             length0;
        u32                             length1;
-       u32                             i;
+       acpi_status                     status = AE_OK;
+       u8                              local_result = FALSE;
+       int                             compare;
 
 
-       ACPI_FUNCTION_ENTRY ();
+       ACPI_FUNCTION_TRACE ("ex_do_logical_op");
 
 
-       if (ACPI_GET_OBJECT_TYPE (obj_desc0) == ACPI_TYPE_INTEGER) {
-               /* Both operands are of type integer */
+       /*
+        * Convert the second operand if necessary.  The first operand
+        * determines the type of the second operand, (See the Data Types
+        * section of the ACPI 3.0+ specification.)  Both object types are
+        * guaranteed to be either Integer/String/Buffer by the operand
+        * resolution mechanism.
+        */
+       switch (ACPI_GET_OBJECT_TYPE (operand0)) {
+       case ACPI_TYPE_INTEGER:
+               status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16);
+               break;
 
-               operand0 = obj_desc0->integer.value;
-               operand1 = obj_desc1->integer.value;
+       case ACPI_TYPE_STRING:
+               status = acpi_ex_convert_to_string (operand1, &local_operand1,
+                                ACPI_IMPLICIT_CONVERT_HEX);
+               break;
 
-               switch (opcode) {
-               case AML_LAND_OP:               /* LAnd (Operand0, Operand1) */
+       case ACPI_TYPE_BUFFER:
+               status = acpi_ex_convert_to_buffer (operand1, &local_operand1);
+               break;
 
-                       if (operand0 && operand1) {
-                               return (TRUE);
-                       }
-                       break;
+       default:
+               status = AE_AML_INTERNAL;
+               break;
+       }
+
+       if (ACPI_FAILURE (status)) {
+               goto cleanup;
+       }
 
+       /*
+        * Two cases: 1) Both Integers, 2) Both Strings or Buffers
+        */
+       if (ACPI_GET_OBJECT_TYPE (operand0) == ACPI_TYPE_INTEGER) {
+               /*
+                * 1) Both operands are of type integer
+                *    Note: local_operand1 may have changed above
+                */
+               integer0 = operand0->integer.value;
+               integer1 = local_operand1->integer.value;
+
+               switch (opcode) {
                case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
 
-                       if (operand0 == operand1) {
-                               return (TRUE);
+                       if (integer0 == integer1) {
+                               local_result = TRUE;
                        }
                        break;
 
                case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
 
-                       if (operand0 > operand1) {
-                               return (TRUE);
+                       if (integer0 > integer1) {
+                               local_result = TRUE;
                        }
                        break;
 
                case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
 
-                       if (operand0 < operand1) {
-                               return (TRUE);
-                       }
-                       break;
-
-               case AML_LOR_OP:                 /* LOr (Operand0, Operand1) */
-
-                       if (operand0 || operand1) {
-                               return (TRUE);
+                       if (integer0 < integer1) {
+                               local_result = TRUE;
                        }
                        break;
 
                default:
+                       status = AE_AML_INTERNAL;
                        break;
                }
        }
        else {
                /*
-                * Case for Buffer/String objects.
-                * NOTE: takes advantage of common Buffer/String object fields
+                * 2) Both operands are Strings or both are Buffers
+                *    Note: Code below takes advantage of common Buffer/String
+                *          object fields. local_operand1 may have changed above. Use
+                *          memcmp to handle nulls in buffers.
                 */
-               length0 = obj_desc0->buffer.length;
-               ptr0    = obj_desc0->buffer.pointer;
+               length0 = operand0->buffer.length;
+               length1 = local_operand1->buffer.length;
 
-               length1 = obj_desc1->buffer.length;
-               ptr1    = obj_desc1->buffer.pointer;
+               /* Lexicographic compare: compare the data bytes */
+
+               compare = ACPI_MEMCMP ((const char * ) operand0->buffer.pointer,
+                                (const char * ) local_operand1->buffer.pointer,
+                                (length0 > length1) ? length1 : length0);
 
                switch (opcode) {
                case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
 
                        /* Length and all bytes must be equal */
 
-                       if (length0 != length1) {
-                               return (FALSE);
-                       }
+                       if ((length0 == length1) &&
+                               (compare == 0)) {
+                               /* Length and all bytes match ==> TRUE */
 
-                       for (i = 0; i < length0; i++) {
-                               if (ptr0[i] != ptr1[i]) {
-                                       return (FALSE);
-                               }
+                               local_result = TRUE;
                        }
-                       return (TRUE);
+                       break;
 
                case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
 
-                       /* Lexicographic compare:  Scan the 1-to-1 data */
-
-                       for (i = 0; (i < length0) && (i < length1); i++) {
-                               if (ptr0[i] > ptr1[i]) {
-                                       return (TRUE);
-                               }
+                       if (compare > 0) {
+                               local_result = TRUE;
+                               goto cleanup;   /* TRUE */
+                       }
+                       if (compare < 0) {
+                               goto cleanup;   /* FALSE */
                        }
 
-                       /* Bytes match, now check lengths */
+                       /* Bytes match (to shortest length), compare lengths */
 
                        if (length0 > length1) {
-                               return (TRUE);
+                               local_result = TRUE;
                        }
-
-                       /* Length0 <= Length1 */
-
-                       return (FALSE);
+                       break;
 
                case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
 
-                       /* Lexicographic compare:  Scan the 1-to-1 data */
-
-                       for (i = 0; (i < length0) && (i < length1); i++) {
-                               if (ptr0[i] < ptr1[i]) {
-                                       return (TRUE);
-                               }
+                       if (compare > 0) {
+                               goto cleanup;   /* FALSE */
+                       }
+                       if (compare < 0) {
+                               local_result = TRUE;
+                               goto cleanup;   /* TRUE */
                        }
 
-                       /* Bytes match, now check lengths */
+                       /* Bytes match (to shortest length), compare lengths */
 
                        if (length0 < length1) {
-                               return (TRUE);
+                               local_result = TRUE;
                        }
-
-                       /* Length0 >= Length1 */
-
-                       return (FALSE);
+                       break;
 
                default:
+                       status = AE_AML_INTERNAL;
                        break;
                }
        }
 
-       return (FALSE);
+cleanup:
+
+       /* New object was created if implicit conversion performed - delete */
+
+       if (local_operand1 != operand1) {
+               acpi_ut_remove_reference (local_operand1);
+       }
+
+       /* Return the logical result and status */
+
+       *logical_result = local_result;
+       return_ACPI_STATUS (status);
 }
 
 
index 8ba1e64..6e31939 100644 (file)
@@ -67,7 +67,7 @@
  * Where:
  *
  * xA - ARGUMENTS:    The number of arguments (input operands) that are
- *                    required for this opcode type (1 through 6 args).
+ *                    required for this opcode type (0 through 6 args).
  * yT - TARGETS:      The number of targets (output operands) that are required
  *                    for this opcode type (0, 1, or 2 targets).
  * zR - RETURN VALUE: Indicates whether this opcode type returns a value
  * fully resolved operands.
 !*/
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_opcode_0A_0T_1R
+ *
+ * PARAMETERS:  walk_state          - Current state (contains AML opcode)
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Execute operator with no operands, one return value
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_0A_0T_1R (
+       struct acpi_walk_state          *walk_state)
+{
+       acpi_status                     status = AE_OK;
+       union acpi_operand_object       *return_desc = NULL;
+
+
+       ACPI_FUNCTION_TRACE_STR ("ex_opcode_0A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+       /* Examine the AML opcode */
+
+       switch (walk_state->opcode) {
+       case AML_TIMER_OP:      /*  Timer () */
+
+               /* Create a return object of type Integer */
+
+               return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+               if (!return_desc) {
+                       status = AE_NO_MEMORY;
+                       goto cleanup;
+               }
+
+               return_desc->integer.value = acpi_os_get_timer ();
+               break;
+
+       default:                /*  Unknown opcode  */
+
+               ACPI_REPORT_ERROR (("acpi_ex_opcode_0A_0T_1R: Unknown opcode %X\n",
+                       walk_state->opcode));
+               status = AE_AML_BAD_OPCODE;
+               break;
+       }
+
+cleanup:
+
+       if (!walk_state->result_obj) {
+               walk_state->result_obj = return_desc;
+       }
+
+       /* Delete return object on error */
+
+       if (ACPI_FAILURE (status)) {
+               acpi_ut_remove_reference (return_desc);
+       }
+
+       return_ACPI_STATUS (status);
+}
+
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_opcode_1A_0T_0R
@@ -124,7 +187,7 @@ acpi_ex_opcode_1A_0T_0R (
 
        case AML_SLEEP_OP:      /*  Sleep (msec_time) */
 
-               status = acpi_ex_system_do_suspend ((u32) operand[0]->integer.value);
+               status = acpi_ex_system_do_suspend (operand[0]->integer.value);
                break;
 
 
@@ -222,7 +285,7 @@ acpi_ex_opcode_1A_1T_1R (
        union acpi_operand_object       *return_desc2 = NULL;
        u32                             temp32;
        u32                             i;
-       u32                             power_of_ten;
+       acpi_integer                    power_of_ten;
        acpi_integer                    digit;
 
 
@@ -262,7 +325,8 @@ acpi_ex_opcode_1A_1T_1R (
                         * Acpi specification describes Integer type as a little
                         * endian unsigned value, so this boundary condition is valid.
                         */
-                       for (temp32 = 0; return_desc->integer.value && temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) {
+                       for (temp32 = 0; return_desc->integer.value &&
+                                          temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) {
                                return_desc->integer.value >>= 1;
                        }
 
@@ -278,13 +342,15 @@ acpi_ex_opcode_1A_1T_1R (
                         * The Acpi specification describes Integer type as a little
                         * endian unsigned value, so this boundary condition is valid.
                         */
-                       for (temp32 = 0; return_desc->integer.value && temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) {
+                       for (temp32 = 0; return_desc->integer.value &&
+                                          temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) {
                                return_desc->integer.value <<= 1;
                        }
 
                        /* Since the bit position is one-based, subtract from 33 (65) */
 
-                       return_desc->integer.value = temp32 == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - temp32;
+                       return_desc->integer.value = temp32 == 0 ? 0 :
+                                         (ACPI_INTEGER_BIT_SIZE + 1) - temp32;
                        break;
 
 
@@ -319,7 +385,8 @@ acpi_ex_opcode_1A_1T_1R (
 
                                /* Sum the digit into the result with the current power of 10 */
 
-                               return_desc->integer.value += (((acpi_integer) temp32) * power_of_ten);
+                               return_desc->integer.value += (((acpi_integer) temp32) *
+                                                power_of_ten);
 
                                /* Shift to next BCD digit */
 
@@ -340,18 +407,20 @@ acpi_ex_opcode_1A_1T_1R (
                        /* Each BCD digit is one nybble wide */
 
                        for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) {
-                               (void) acpi_ut_short_divide (&digit, 10, &digit, &temp32);
+                               (void) acpi_ut_short_divide (digit, 10, &digit, &temp32);
 
                                /* Insert the BCD digit that resides in the remainder from above */
 
-                               return_desc->integer.value |= (((acpi_integer) temp32) << (i * 4));
+                               return_desc->integer.value |= (((acpi_integer) temp32) <<
+                                                  ACPI_MUL_4 (i));
                        }
 
                        /* Overflow if there is any data left in Digit */
 
                        if (digit > 0) {
-                               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Integer too large to convert to BCD: %8.8X%8.8X\n",
-                                               ACPI_FORMAT_UINT64 (operand[0]->integer.value)));
+                               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+                                       "Integer too large to convert to BCD: %8.8X%8.8X\n",
+                                       ACPI_FORMAT_UINT64 (operand[0]->integer.value)));
                                status = AE_AML_NUMERIC_OVERFLOW;
                                goto cleanup;
                        }
@@ -429,42 +498,47 @@ acpi_ex_opcode_1A_1T_1R (
         */
        case AML_COPY_OP:               /* Copy (Source, Target) */
 
-               status = acpi_ut_copy_iobject_to_iobject (operand[0], &return_desc, walk_state);
+               status = acpi_ut_copy_iobject_to_iobject (operand[0], &return_desc,
+                                walk_state);
                break;
 
 
        case AML_TO_DECSTRING_OP:       /* to_decimal_string (Data, Result) */
 
-               status = acpi_ex_convert_to_string (operand[0], &return_desc, 10, ACPI_UINT32_MAX, walk_state);
+               status = acpi_ex_convert_to_string (operand[0], &return_desc,
+                                ACPI_EXPLICIT_CONVERT_DECIMAL);
                break;
 
 
        case AML_TO_HEXSTRING_OP:       /* to_hex_string (Data, Result) */
 
-               status = acpi_ex_convert_to_string (operand[0], &return_desc, 16, ACPI_UINT32_MAX, walk_state);
+               status = acpi_ex_convert_to_string (operand[0], &return_desc,
+                                ACPI_EXPLICIT_CONVERT_HEX);
                break;
 
 
        case AML_TO_BUFFER_OP:          /* to_buffer (Data, Result) */
 
-               status = acpi_ex_convert_to_buffer (operand[0], &return_desc, walk_state);
+               status = acpi_ex_convert_to_buffer (operand[0], &return_desc);
                break;
 
 
        case AML_TO_INTEGER_OP:         /* to_integer (Data, Result) */
 
-               status = acpi_ex_convert_to_integer (operand[0], &return_desc, walk_state);
+               status = acpi_ex_convert_to_integer (operand[0], &return_desc,
+                                ACPI_ANY_BASE);
                break;
 
 
-       case AML_SHIFT_LEFT_BIT_OP:     /*  shift_left_bit (Source, bit_num) */
-       case AML_SHIFT_RIGHT_BIT_OP:    /*  shift_right_bit (Source, bit_num) */
+       case AML_SHIFT_LEFT_BIT_OP:     /* shift_left_bit (Source, bit_num) */
+       case AML_SHIFT_RIGHT_BIT_OP:    /* shift_right_bit (Source, bit_num) */
 
                /*
                 * These are two obsolete opcodes
                 */
-               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s is obsolete and not implemented\n",
-                                 acpi_ps_get_opcode_name (walk_state->opcode)));
+               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+                       "%s is obsolete and not implemented\n",
+                       acpi_ps_get_opcode_name (walk_state->opcode)));
                status = AE_SUPPORT;
                goto cleanup;
 
@@ -537,7 +611,13 @@ acpi_ex_opcode_1A_0T_1R (
                        goto cleanup;
                }
 
-               return_desc->integer.value = !operand[0]->integer.value;
+               /*
+                * Set result to ONES (TRUE) if Value == 0.  Note:
+                * return_desc->Integer.Value is initially == 0 (FALSE) from above.
+                */
+               if (!operand[0]->integer.value) {
+                       return_desc->integer.value = ACPI_INTEGER_MAX;
+               }
                break;
 
 
@@ -545,54 +625,80 @@ acpi_ex_opcode_1A_0T_1R (
        case AML_INCREMENT_OP:          /* Increment (Operand)  */
 
                /*
-                * Since we are expecting a Reference operand, it
-                * can be either a NS Node or an internal object.
+                * Create a new integer.  Can't just get the base integer and
+                * increment it because it may be an Arg or Field.
+                */
+               return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+               if (!return_desc) {
+                       status = AE_NO_MEMORY;
+                       goto cleanup;
+               }
+
+               /*
+                * Since we are expecting a Reference operand, it can be either a
+                * NS Node or an internal object.
                 */
-               return_desc = operand[0];
-               if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) == ACPI_DESC_TYPE_OPERAND) {
+               temp_desc = operand[0];
+               if (ACPI_GET_DESCRIPTOR_TYPE (temp_desc) == ACPI_DESC_TYPE_OPERAND) {
                        /* Internal reference object - prevent deletion */
 
-                       acpi_ut_add_reference (return_desc);
+                       acpi_ut_add_reference (temp_desc);
                }
 
                /*
-                * Convert the return_desc Reference to a Number
-                * (This removes a reference on the return_desc object)
+                * Convert the Reference operand to an Integer (This removes a
+                * reference on the Operand[0] object)
+                *
+                * NOTE:  We use LNOT_OP here in order to force resolution of the
+                * reference operand to an actual integer.
                 */
-               status = acpi_ex_resolve_operands (AML_LNOT_OP, &return_desc, walk_state);
+               status = acpi_ex_resolve_operands (AML_LNOT_OP, &temp_desc, walk_state);
                if (ACPI_FAILURE (status)) {
                        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s: bad operand(s) %s\n",
-                               acpi_ps_get_opcode_name (walk_state->opcode), acpi_format_exception(status)));
+                               acpi_ps_get_opcode_name (walk_state->opcode),
+                               acpi_format_exception(status)));
 
                        goto cleanup;
                }
 
                /*
-                * return_desc is now guaranteed to be an Integer object
-                * Do the actual increment or decrement
+                * temp_desc is now guaranteed to be an Integer object --
+                * Perform the actual increment or decrement
                 */
-               if (AML_INCREMENT_OP == walk_state->opcode) {
-                       return_desc->integer.value++;
+               if (walk_state->opcode == AML_INCREMENT_OP) {
+                       return_desc->integer.value = temp_desc->integer.value +1;
                }
                else {
-                       return_desc->integer.value--;
+                       return_desc->integer.value = temp_desc->integer.value -1;
                }
 
-               /* Store the result back in the original descriptor */
+               /* Finished with this Integer object */
+
+               acpi_ut_remove_reference (temp_desc);
 
+               /*
+                * Store the result back (indirectly) through the original
+                * Reference object
+                */
                status = acpi_ex_store (return_desc, operand[0], walk_state);
                break;
 
 
        case AML_TYPE_OP:               /* object_type (source_object) */
 
+               /*
+                * Note: The operand is not resolved at this point because we want to
+                * get the associated object, not its value.  For example, we don't want
+                * to resolve a field_unit to its value, we want the actual field_unit
+                * object.
+                */
+
                /* Get the type of the base object */
 
                status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, NULL);
                if (ACPI_FAILURE (status)) {
                        goto cleanup;
                }
-
                /* Allocate a descriptor to hold the type. */
 
                return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
@@ -607,6 +713,11 @@ acpi_ex_opcode_1A_0T_1R (
 
        case AML_SIZE_OF_OP:            /* size_of (source_object) */
 
+               /*
+                * Note: The operand is not resolved at this point because we want to
+                * get the associated object, not its value.
+                */
+
                /* Get the base object */
 
                status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, &temp_desc);
@@ -615,11 +726,19 @@ acpi_ex_opcode_1A_0T_1R (
                }
 
                /*
-                * Type is guaranteed to be a buffer, string, or package at this
-                * point (even if the original operand was an object reference, it
-                * will be resolved and typechecked during operand resolution.)
+                * The type of the base object must be integer, buffer, string, or
+                * package.  All others are not supported.
+                *
+                * NOTE: Integer is not specifically supported by the ACPI spec,
+                * but is supported implicitly via implicit operand conversion.
+                * rather than bother with conversion, we just use the byte width
+                * global (4 or 8 bytes).
                 */
                switch (type) {
+               case ACPI_TYPE_INTEGER:
+                       value = acpi_gbl_integer_byte_width;
+                       break;
+
                case ACPI_TYPE_BUFFER:
                        value = temp_desc->buffer.length;
                        break;
@@ -633,7 +752,8 @@ acpi_ex_opcode_1A_0T_1R (
                        break;
 
                default:
-                       ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "size_of, Not Buf/Str/Pkg - found type %s\n",
+                       ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+                               "size_of - Operand is not Buf/Int/Str/Pkg - found type %s\n",
                                acpi_ut_get_type_name (type)));
                        status = AE_AML_OPERAND_TYPE;
                        goto cleanup;
@@ -803,7 +923,8 @@ acpi_ex_opcode_1A_0T_1R (
                                                 * an uninitialized package element and is thus a
                                                 * severe error.
                                                 */
-                                               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "NULL package element obj %p\n",
+                                               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+                                                       "NULL package element obj %p\n",
                                                        operand[0]));
                                                status = AE_AML_UNINITIALIZED_ELEMENT;
                                                goto cleanup;
@@ -815,7 +936,8 @@ acpi_ex_opcode_1A_0T_1R (
 
                                default:
 
-                                       ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Index target_type %X in obj %p\n",
+                                       ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+                                               "Unknown Index target_type %X in obj %p\n",
                                                operand[0]->reference.target_type, operand[0]));
                                        status = AE_AML_OPERAND_TYPE;
                                        goto cleanup;
@@ -839,7 +961,8 @@ acpi_ex_opcode_1A_0T_1R (
 
 
                        default:
-                               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown opcode in ref(%p) - %X\n",
+                               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+                                       "Unknown opcode in ref(%p) - %X\n",
                                        operand[0], operand[0]->reference.opcode));
 
                                status = AE_TYPE;
index c5c6dd8..0834af8 100644 (file)
@@ -508,6 +508,7 @@ acpi_ex_prep_field_value (
 
                if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) {
                        ACPI_REPORT_ERROR (("Null Index Object during field prep\n"));
+                       acpi_ut_delete_object_desc (obj_desc);
                        return_ACPI_STATUS (AE_AML_INTERNAL);
                }
 
index 3262f1a..4fef755 100644 (file)
@@ -121,7 +121,7 @@ acpi_ex_system_memory_space_handler (
         * Hardware does not support non-aligned data transfers, we must verify
         * the request.
         */
-       (void) acpi_ut_short_divide ((acpi_integer *) &address, length, NULL, &remainder);
+       (void) acpi_ut_short_divide ((acpi_integeraddress, length, NULL, &remainder);
        if (remainder != 0) {
                return_ACPI_STATUS (AE_AML_ALIGNMENT);
        }
index 504d53f..c339d74 100644 (file)
@@ -327,11 +327,44 @@ acpi_ex_resolve_multiple (
        union acpi_operand_object       *obj_desc = (void *) operand;
        struct acpi_namespace_node      *node;
        acpi_object_type                type;
+       acpi_status                     status;
 
 
        ACPI_FUNCTION_TRACE ("acpi_ex_resolve_multiple");
 
 
+       /*
+        * Operand can be either a namespace node or an operand descriptor
+        */
+       switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
+       case ACPI_DESC_TYPE_OPERAND:
+               type = obj_desc->common.type;
+               break;
+
+       case ACPI_DESC_TYPE_NAMED:
+               type = ((struct acpi_namespace_node *) obj_desc)->type;
+               obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) obj_desc);
+
+               /* If we had an Alias node, use the attached object for type info */
+
+               if (type == ACPI_TYPE_LOCAL_ALIAS) {
+                       type = ((struct acpi_namespace_node *) obj_desc)->type;
+                       obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) obj_desc);
+               }
+               break;
+
+       default:
+               return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+       }
+
+
+       /*
+        * If type is anything other than a reference, we are done
+        */
+       if (type != ACPI_TYPE_LOCAL_REFERENCE) {
+               goto exit;
+       }
+
        /*
         * For reference objects created via the ref_of or Index operators,
         * we need to get to the base object (as per the ACPI specification
@@ -424,6 +457,33 @@ acpi_ex_resolve_multiple (
                        break;
 
 
+               case AML_LOCAL_OP:
+               case AML_ARG_OP:
+
+                       if (return_desc) {
+                               status = acpi_ds_method_data_get_value (obj_desc->reference.opcode,
+                                                 obj_desc->reference.offset, walk_state, &obj_desc);
+                               if (ACPI_FAILURE (status)) {
+                                       return_ACPI_STATUS (status);
+                               }
+                               acpi_ut_remove_reference (obj_desc);
+                       }
+                       else {
+                               status = acpi_ds_method_data_get_node (obj_desc->reference.opcode,
+                                                obj_desc->reference.offset, walk_state, &node);
+                               if (ACPI_FAILURE (status)) {
+                                       return_ACPI_STATUS (status);
+                               }
+
+                               obj_desc = acpi_ns_get_attached_object (node);
+                               if (!obj_desc) {
+                                       type = ACPI_TYPE_ANY;
+                                       goto exit;
+                               }
+                       }
+                       break;
+
+
                case AML_DEBUG_OP:
 
                        /* The Debug Object is of type "debug_object" */
index d410bd7..51df1a7 100644 (file)
@@ -160,7 +160,7 @@ acpi_ex_resolve_operands (
                return_ACPI_STATUS (AE_AML_INTERNAL);
        }
 
-       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] operand_types=%X \n",
+       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] required_operand_types=%8.8X \n",
                opcode, op_info->name, arg_types));
 
        /*
@@ -227,12 +227,13 @@ acpi_ex_resolve_operands (
                                case AML_LOAD_OP:   /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
 
                                        ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
-                                               "Reference Opcode: %s\n", op_info->name)));
+                                               "Operand is a Reference, ref_opcode [%s]\n",
+                                               (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name)));
                                        break;
 
                                default:
                                        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-                                               "Unknown Reference Opcode %X [%s]\n",
+                                               "Operand is a Reference, Unknown Reference Opcode %X [%s]\n",
                                                obj_desc->reference.opcode,
                                                (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name));
 
@@ -398,7 +399,7 @@ acpi_ex_resolve_operands (
                         * But we can implicitly convert from a STRING or BUFFER
                         * Aka - "Implicit Source Operand Conversion"
                         */
-                       status = acpi_ex_convert_to_integer (obj_desc, stack_ptr, walk_state);
+                       status = acpi_ex_convert_to_integer (obj_desc, stack_ptr, 16);
                        if (ACPI_FAILURE (status)) {
                                if (status == AE_TYPE) {
                                        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
@@ -420,7 +421,7 @@ acpi_ex_resolve_operands (
                         * But we can implicitly convert from a STRING or INTEGER
                         * Aka - "Implicit Source Operand Conversion"
                         */
-                       status = acpi_ex_convert_to_buffer (obj_desc, stack_ptr, walk_state);
+                       status = acpi_ex_convert_to_buffer (obj_desc, stack_ptr);
                        if (ACPI_FAILURE (status)) {
                                if (status == AE_TYPE) {
                                        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
@@ -442,7 +443,8 @@ acpi_ex_resolve_operands (
                         * But we can implicitly convert from a BUFFER or INTEGER
                         * Aka - "Implicit Source Operand Conversion"
                         */
-                       status = acpi_ex_convert_to_string (obj_desc, stack_ptr, 16, ACPI_UINT32_MAX, walk_state);
+                       status = acpi_ex_convert_to_string (obj_desc, stack_ptr,
+                                        ACPI_IMPLICIT_CONVERT_HEX);
                        if (ACPI_FAILURE (status)) {
                                if (status == AE_TYPE) {
                                        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
@@ -494,7 +496,7 @@ acpi_ex_resolve_operands (
 
                                /* Highest priority conversion is to type Buffer */
 
-                               status = acpi_ex_convert_to_buffer (obj_desc, stack_ptr, walk_state);
+                               status = acpi_ex_convert_to_buffer (obj_desc, stack_ptr);
                                if (ACPI_FAILURE (status)) {
                                        return_ACPI_STATUS (status);
                                }
index 25464f7..33fbfed 100644 (file)
@@ -129,7 +129,8 @@ acpi_ex_store (
                /* Destination is not a Reference object */
 
                ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-                       "Destination is not a Reference or Constant object [%p]\n", dest_desc));
+                       "Target is not a Reference or Constant object - %s [%p]\n",
+                       acpi_ut_get_object_type_name (dest_desc), dest_desc));
 
                ACPI_DUMP_STACK_ENTRY (source_desc);
                ACPI_DUMP_STACK_ENTRY (dest_desc);
@@ -182,23 +183,37 @@ acpi_ex_store (
                 * Storing to the Debug object causes the value stored to be
                 * displayed and otherwise has no effect -- see ACPI Specification
                 */
-               ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "**** Write to Debug Object: ****:\n\n"));
+               ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+                       "**** Write to Debug Object: Object %p %s ****:\n\n",
+                       source_desc, acpi_ut_get_object_type_name (source_desc)));
 
                ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %s: ",
-                                 acpi_ut_get_object_type_name (source_desc)));
+                       acpi_ut_get_object_type_name (source_desc)));
+
+               if (!acpi_ut_valid_internal_object (source_desc)) {
+                  ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT,
+                          "%p, Invalid Internal Object!\n", source_desc));
+                  break;
+               }
 
                switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
                case ACPI_TYPE_INTEGER:
 
-                       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n",
+                       if (acpi_gbl_integer_byte_width == 4) {
+                               ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n",
+                                       (u32) source_desc->integer.value));
+                       }
+                       else {
+                               ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n",
                                        ACPI_FORMAT_UINT64 (source_desc->integer.value)));
+                       }
                        break;
 
 
                case ACPI_TYPE_BUFFER:
 
-                       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length 0x%.2X",
-                                       (u32) source_desc->buffer.length));
+                       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]",
+                               (u32) source_desc->buffer.length));
                        ACPI_DUMP_BUFFER (source_desc->buffer.pointer,
                                (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32);
                        break;
@@ -206,22 +221,22 @@ acpi_ex_store (
 
                case ACPI_TYPE_STRING:
 
-                       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length 0x%.2X, \"%s\"\n",
-                                       source_desc->string.length, source_desc->string.pointer));
+                       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n",
+                               source_desc->string.length, source_desc->string.pointer));
                        break;
 
 
                case ACPI_TYPE_PACKAGE:
 
-                       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Size 0x%.2X Elements Ptr - %p\n",
-                                       source_desc->package.count, source_desc->package.elements));
+                       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] Elements Ptr - %p\n",
+                               source_desc->package.count, source_desc->package.elements));
                        break;
 
 
                default:
 
                        ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p\n",
-                                       source_desc));
+                               source_desc));
                        break;
                }
 
index 42a1332..46e5fa6 100644 (file)
@@ -167,7 +167,7 @@ acpi_ex_system_do_stall (
 
 acpi_status
 acpi_ex_system_do_suspend (
-       u32                             how_long)
+       acpi_integer                    how_long)
 {
        acpi_status                     status;
 
@@ -179,8 +179,7 @@ acpi_ex_system_do_suspend (
 
        acpi_ex_exit_interpreter ();
 
-       acpi_os_sleep ((u16) (how_long / (u32) 1000),
-                         (u16) (how_long % (u32) 1000));
+       acpi_os_sleep (how_long);
 
        /* And now we must get the interpreter again */
 
index bc425b2..85253b3 100644 (file)
@@ -280,25 +280,25 @@ acpi_ex_digits_needed (
 {
        u32                             num_digits;
        acpi_integer                    current_value;
-       acpi_integer                    quotient;
 
 
        ACPI_FUNCTION_TRACE ("ex_digits_needed");
 
 
-       /*
-        * acpi_integer is unsigned, so we don't worry about a '-'
-        */
-       if ((current_value = value) == 0) {
+       /* acpi_integer is unsigned, so we don't worry about a '-' prefix */
+
+       if (value == 0) {
                return_VALUE (1);
        }
 
+       current_value = value;
        num_digits = 0;
 
+       /* Count the digits in the requested base */
+
        while (current_value) {
-               (void) acpi_ut_short_divide (&current_value, base, &quotient, NULL);
+               (void) acpi_ut_short_divide (current_value, base, &current_value, NULL);
                num_digits++;
-               current_value = quotient;
        }
 
        return_VALUE (num_digits);
@@ -361,7 +361,6 @@ acpi_ex_unsigned_integer_to_string (
        u32                             count;
        u32                             digits_needed;
        u32                             remainder;
-       acpi_integer                    quotient;
 
 
        ACPI_FUNCTION_ENTRY ();
@@ -371,9 +370,8 @@ acpi_ex_unsigned_integer_to_string (
        out_string[digits_needed] = 0;
 
        for (count = digits_needed; count > 0; count--) {
-               (void) acpi_ut_short_divide (&value, 10, &quotient, &remainder);
+               (void) acpi_ut_short_divide (value, 10, &value, &remainder);
                out_string[count-1] = (char) ('0' + remainder);\
-               value = quotient;
        }
 }
 
index 97989bc..438ad37 100644 (file)
@@ -2,6 +2,8 @@
 # Makefile for all Linux ACPI interpreter subdirectories
 #
 
-obj-y := hwacpi.o  hwgpe.o  hwregs.o  hwsleep.o  hwtimer.o
+obj-y := hwacpi.o  hwgpe.o  hwregs.o  hwsleep.o
+
+obj-$(ACPI_FUTURE_USAGE) += hwtimer.o
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
index 3910b5e..e4f17ac 100644 (file)
@@ -135,7 +135,7 @@ acpi_hw_clear_gpe (
  * DESCRIPTION: Return the status of a single GPE.
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_hw_get_gpe_status (
        struct acpi_gpe_event_info      *gpe_event_info,
@@ -194,6 +194,7 @@ acpi_hw_get_gpe_status (
 unlock_and_exit:
        return (status);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /******************************************************************************
index cb998fe..11daf53 100644 (file)
@@ -43,6 +43,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
@@ -211,6 +212,7 @@ acpi_get_sleep_type_data (
        acpi_ut_remove_reference (info.return_object);
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_get_sleep_type_data);
 
 
 /*******************************************************************************
@@ -307,6 +309,7 @@ acpi_get_register (
 
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_get_register);
 
 
 /*******************************************************************************
@@ -457,6 +460,7 @@ unlock_and_exit:
                        value, register_value, bit_reg_info->parent_register));
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_set_register);
 
 
 /******************************************************************************
@@ -709,6 +713,7 @@ acpi_hw_low_level_read (
        u32                             *value,
        struct acpi_generic_address     *reg)
 {
+       u64                             address;
        acpi_status                     status;
 
 
@@ -720,8 +725,14 @@ acpi_hw_low_level_read (
         * a non-zero address within. However, don't return an error
         * because the PM1A/B code must not fail if B isn't present.
         */
-       if ((!reg) ||
-               (!reg->address)) {
+       if (!reg) {
+               return (AE_OK);
+       }
+
+       /* Get a local copy of the address.  Handles possible alignment issues */
+
+       ACPI_MOVE_64_TO_64 (&address, &reg->address);
+       if (!address) {
                return (AE_OK);
        }
        *value = 0;
@@ -734,14 +745,14 @@ acpi_hw_low_level_read (
        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
 
                status = acpi_os_read_memory (
-                                (acpi_physical_address) reg->address,
+                                (acpi_physical_address) address,
                                 value, width);
                break;
 
 
        case ACPI_ADR_SPACE_SYSTEM_IO:
 
-               status = acpi_os_read_port ((acpi_io_address) reg->address,
+               status = acpi_os_read_port ((acpi_io_address) address,
                                 value, width);
                break;
 
@@ -754,7 +765,7 @@ acpi_hw_low_level_read (
 
        ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
                        *value, width,
-                       ACPI_FORMAT_UINT64 (reg->address),
+                       ACPI_FORMAT_UINT64 (address),
                        acpi_ut_get_region_name (reg->address_space_id)));
 
        return (status);
@@ -781,6 +792,7 @@ acpi_hw_low_level_write (
        u32                             value,
        struct acpi_generic_address     *reg)
 {
+       u64                             address;
        acpi_status                     status;
 
 
@@ -792,8 +804,14 @@ acpi_hw_low_level_write (
         * a non-zero address within. However, don't return an error
         * because the PM1A/B code must not fail if B isn't present.
         */
-       if ((!reg) ||
-               (!reg->address)) {
+       if (!reg) {
+               return (AE_OK);
+       }
+
+       /* Get a local copy of the address.  Handles possible alignment issues */
+
+       ACPI_MOVE_64_TO_64 (&address, &reg->address);
+       if (!address) {
                return (AE_OK);
        }
 
@@ -805,14 +823,14 @@ acpi_hw_low_level_write (
        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
 
                status = acpi_os_write_memory (
-                                (acpi_physical_address) reg->address,
+                                (acpi_physical_address) address,
                                 value, width);
                break;
 
 
        case ACPI_ADR_SPACE_SYSTEM_IO:
 
-               status = acpi_os_write_port ((acpi_io_address) reg->address,
+               status = acpi_os_write_port ((acpi_io_address) address,
                                 value, width);
                break;
 
@@ -825,7 +843,7 @@ acpi_hw_low_level_write (
 
        ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
                        value, width,
-                       ACPI_FORMAT_UINT64 (reg->address),
+                       ACPI_FORMAT_UINT64 (address),
                        acpi_ut_get_region_name (reg->address_space_id)));
 
        return (status);
index 6ffa80b..3467380 100644 (file)
@@ -42,6 +42,8 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
+
 #include <acpi/acpi.h>
 
 #define _COMPONENT          ACPI_HARDWARE
@@ -110,7 +112,7 @@ acpi_set_firmware_waking_vector (
  * DESCRIPTION: Access function for firmware_waking_vector field in FACS
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_get_firmware_waking_vector (
        acpi_physical_address *physical_address)
@@ -136,6 +138,7 @@ acpi_get_firmware_waking_vector (
 
        return_ACPI_STATUS (AE_OK);
 }
+#endif
 
 
 /******************************************************************************
@@ -391,6 +394,7 @@ acpi_enter_sleep_state (
 
        return_ACPI_STATUS (AE_OK);
 }
+EXPORT_SYMBOL(acpi_enter_sleep_state);
 
 
 /******************************************************************************
@@ -456,6 +460,7 @@ acpi_enter_sleep_state_s4bios (
 
        return_ACPI_STATUS (AE_OK);
 }
+EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios);
 
 
 /******************************************************************************
index 1f94d6f..458120e 100644 (file)
@@ -42,6 +42,8 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
+
 #include <acpi/acpi.h>
 
 #define _COMPONENT          ACPI_HARDWARE
@@ -112,6 +114,7 @@ acpi_get_timer (
 
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_get_timer);
 
 
 /******************************************************************************
@@ -149,10 +152,9 @@ acpi_get_timer_duration (
        u32                             end_ticks,
        u32                             *time_elapsed)
 {
-       u32                             delta_ticks = 0;
-       union uint64_overlay            normalized_ticks;
        acpi_status                     status;
-       acpi_integer                    out_quotient;
+       u32                             delta_ticks;
+       acpi_integer                    quotient;
 
 
        ACPI_FUNCTION_TRACE ("acpi_get_timer_duration");
@@ -164,7 +166,7 @@ acpi_get_timer_duration (
 
        /*
         * Compute Tick Delta:
-        * Handle (max one) timer rollovers on 24- versus 32-bit timers.
+        * Handle (max one) timer rollovers on 24-bit versus 32-bit timers.
         */
        if (start_ticks < end_ticks) {
                delta_ticks = end_ticks - start_ticks;
@@ -181,23 +183,21 @@ acpi_get_timer_duration (
                        delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks;
                }
        }
-       else {
+       else /* start_ticks == end_ticks */ {
                *time_elapsed = 0;
                return_ACPI_STATUS (AE_OK);
        }
 
        /*
-        * Compute Duration (Requires a 64-bit divide):
+        * Compute Duration (Requires a 64-bit multiply and divide):
         *
         * time_elapsed = (delta_ticks * 1000000) / PM_TIMER_FREQUENCY;
         */
-       normalized_ticks.full = ((u64) delta_ticks) * 1000000;
+       status = acpi_ut_short_divide (((u64) delta_ticks) * 1000000,
+                        PM_TIMER_FREQUENCY, &quotient, NULL);
 
-       status = acpi_ut_short_divide (&normalized_ticks.full, PM_TIMER_FREQUENCY,
-                          &out_quotient, NULL);
-
-       *time_elapsed = (u32) out_quotient;
+       *time_elapsed = (u32) quotient;
        return_ACPI_STATUS (status);
 }
-
+EXPORT_SYMBOL(acpi_get_timer_duration);
 
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);
index ee9c5d1..61ea707 100644 (file)
@@ -62,7 +62,7 @@ acpi_reserve_io_ranges (struct acpi_resource *res, void *data)
                struct acpi_resource_io *io_res = &res->data.io;
 
                if (io_res->min_base_address != io_res->max_base_address)
-                       return AE_OK;
+                       return_VALUE(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, 
@@ -86,7 +86,7 @@ acpi_reserve_io_ranges (struct acpi_resource *res, void *data)
 
        if (requested_res)
                requested_res->flags &= ~IORESOURCE_BUSY;
-       return AE_OK;
+       return_VALUE(AE_OK);
 }
 
 static int acpi_motherboard_add (struct acpi_device *device)
index 9462af1..3f63d36 100644 (file)
@@ -2,9 +2,11 @@
 # Makefile for all Linux ACPI interpreter subdirectories
 #
 
-obj-y := nsaccess.o  nsdumpdv.o  nsload.o    nssearch.o  nsxfeval.o \
+obj-y := nsaccess.o  nsload.o    nssearch.o  nsxfeval.o \
         nsalloc.o   nseval.o    nsnames.o   nsutils.o   nsxfname.o \
         nsdump.o    nsinit.o    nsobject.o  nswalk.o    nsxfobj.o  \
         nsparse.o
 
+obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
+
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
index 765217b..6cbe22f 100644 (file)
@@ -161,8 +161,10 @@ acpi_ns_root_initialize (void)
 
 #if defined (_ACPI_ASL_COMPILER) || defined (_ACPI_DUMP_App)
 
-                               /* i_aSL Compiler cheats by putting parameter count in the owner_iD */
-
+                               /*
+                                * i_aSL Compiler cheats by putting parameter count
+                                * in the owner_iD
+                                */
                                new_node->owner_id = obj_desc->method.param_count;
 #else
                                /* Mark this as a very SPECIAL method */
@@ -204,6 +206,7 @@ acpi_ns_root_initialize (void)
                                        status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT,
                                                         1, &obj_desc->mutex.semaphore);
                                        if (ACPI_FAILURE (status)) {
+                                               acpi_ut_remove_reference (obj_desc);
                                                goto unlock_and_exit;
                                        }
 
@@ -219,6 +222,7 @@ acpi_ns_root_initialize (void)
                                        status = acpi_os_create_semaphore (1, 1,
                                                           &obj_desc->mutex.semaphore);
                                        if (ACPI_FAILURE (status)) {
+                                               acpi_ut_remove_reference (obj_desc);
                                                goto unlock_and_exit;
                                        }
                                }
@@ -236,7 +240,8 @@ acpi_ns_root_initialize (void)
 
                        /* Store pointer to value descriptor in the Node */
 
-                       status = acpi_ns_attach_object (new_node, obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc));
+                       status = acpi_ns_attach_object (new_node, obj_desc,
+                                        ACPI_GET_OBJECT_TYPE (obj_desc));
 
                        /* Remove local reference to the object */
 
@@ -462,7 +467,8 @@ acpi_ns_lookup (
                        type = this_node->type;
 
                        ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
-                               "Prefix-only Pathname (Zero name segments), Flags=%X\n", flags));
+                               "Prefix-only Pathname (Zero name segments), Flags=%X\n",
+                               flags));
                        break;
 
                case AML_DUAL_NAME_PREFIX:
@@ -554,7 +560,7 @@ acpi_ns_lookup (
                /* Try to find the single (4 character) ACPI name */
 
                status = acpi_ns_search_and_enter (simple_name, walk_state, current_node,
-                                 interpreter_mode, this_search_type, local_flags, &this_node);
+                                interpreter_mode, this_search_type, local_flags, &this_node);
                if (ACPI_FAILURE (status)) {
                        if (status == AE_NOT_FOUND) {
                                /* Name not found in ACPI namespace */
index 8afa1dc..57279b2 100644 (file)
@@ -198,7 +198,8 @@ acpi_ns_dump_one_object (
        }
 
        if (!acpi_ut_valid_acpi_name (this_node->name.integer)) {
-               ACPI_REPORT_WARNING (("Invalid ACPI Name %08X\n", this_node->name.integer));
+               ACPI_REPORT_WARNING (("Invalid ACPI Name %08X\n",
+                       this_node->name.integer));
        }
 
        /*
@@ -226,9 +227,8 @@ acpi_ns_dump_one_object (
                case ACPI_TYPE_PROCESSOR:
 
                        acpi_os_printf ("ID %X Len %.4X Addr %p\n",
-                                        obj_desc->processor.proc_id,
-                                        obj_desc->processor.length,
-                                        (char *) obj_desc->processor.address);
+                               obj_desc->processor.proc_id, obj_desc->processor.length,
+                               (char *) obj_desc->processor.address);
                        break;
 
 
@@ -241,16 +241,15 @@ acpi_ns_dump_one_object (
                case ACPI_TYPE_METHOD:
 
                        acpi_os_printf ("Args %X Len %.4X Aml %p\n",
-                                        (u32) obj_desc->method.param_count,
-                                        obj_desc->method.aml_length,
-                                        obj_desc->method.aml_start);
+                               (u32) obj_desc->method.param_count,
+                               obj_desc->method.aml_length, obj_desc->method.aml_start);
                        break;
 
 
                case ACPI_TYPE_INTEGER:
 
                        acpi_os_printf ("= %8.8X%8.8X\n",
-                                        ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+                               ACPI_FORMAT_UINT64 (obj_desc->integer.value));
                        break;
 
 
@@ -258,7 +257,7 @@ acpi_ns_dump_one_object (
 
                        if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
                                acpi_os_printf ("Elements %.2X\n",
-                                                obj_desc->package.count);
+                                       obj_desc->package.count);
                        }
                        else {
                                acpi_os_printf ("[Length not yet evaluated]\n");
@@ -298,11 +297,12 @@ acpi_ns_dump_one_object (
 
                case ACPI_TYPE_REGION:
 
-                       acpi_os_printf ("[%s]", acpi_ut_get_region_name (obj_desc->region.space_id));
+                       acpi_os_printf ("[%s]",
+                               acpi_ut_get_region_name (obj_desc->region.space_id));
                        if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
                                acpi_os_printf (" Addr %8.8X%8.8X Len %.4X\n",
-                                                ACPI_FORMAT_UINT64 (obj_desc->region.address),
-                                                obj_desc->region.length);
+                                       ACPI_FORMAT_UINT64 (obj_desc->region.address),
+                                       obj_desc->region.length);
                        }
                        else {
                                acpi_os_printf (" [Address/Length not yet evaluated]\n");
@@ -313,7 +313,7 @@ acpi_ns_dump_one_object (
                case ACPI_TYPE_LOCAL_REFERENCE:
 
                        acpi_os_printf ("[%s]\n",
-                                       acpi_ps_get_opcode_name (obj_desc->reference.opcode));
+                               acpi_ps_get_opcode_name (obj_desc->reference.opcode));
                        break;
 
 
@@ -322,7 +322,7 @@ acpi_ns_dump_one_object (
                        if (obj_desc->buffer_field.buffer_obj &&
                                obj_desc->buffer_field.buffer_obj->buffer.node) {
                                acpi_os_printf ("Buf [%4.4s]",
-                                               acpi_ut_get_node_name (obj_desc->buffer_field.buffer_obj->buffer.node));
+                                       acpi_ut_get_node_name (obj_desc->buffer_field.buffer_obj->buffer.node));
                        }
                        break;
 
@@ -330,30 +330,31 @@ acpi_ns_dump_one_object (
                case ACPI_TYPE_LOCAL_REGION_FIELD:
 
                        acpi_os_printf ("Rgn [%4.4s]",
-                                       acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node));
+                               acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node));
                        break;
 
 
                case ACPI_TYPE_LOCAL_BANK_FIELD:
 
                        acpi_os_printf ("Rgn [%4.4s] Bnk [%4.4s]",
-                                       acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node),
-                                       acpi_ut_get_node_name (obj_desc->bank_field.bank_obj->common_field.node));
+                               acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node),
+                               acpi_ut_get_node_name (obj_desc->bank_field.bank_obj->common_field.node));
                        break;
 
 
                case ACPI_TYPE_LOCAL_INDEX_FIELD:
 
                        acpi_os_printf ("Idx [%4.4s] Dat [%4.4s]",
-                                       acpi_ut_get_node_name (obj_desc->index_field.index_obj->common_field.node),
-                                       acpi_ut_get_node_name (obj_desc->index_field.data_obj->common_field.node));
+                               acpi_ut_get_node_name (obj_desc->index_field.index_obj->common_field.node),
+                               acpi_ut_get_node_name (obj_desc->index_field.data_obj->common_field.node));
                        break;
 
 
                case ACPI_TYPE_LOCAL_ALIAS:
                case ACPI_TYPE_LOCAL_METHOD_ALIAS:
 
-                       acpi_os_printf ("Target %4.4s (%p)\n", acpi_ut_get_node_name (obj_desc), obj_desc);
+                       acpi_os_printf ("Target %4.4s (%p)\n",
+                               acpi_ut_get_node_name (obj_desc), obj_desc);
                        break;
 
                default:
@@ -371,10 +372,10 @@ acpi_ns_dump_one_object (
                case ACPI_TYPE_LOCAL_INDEX_FIELD:
 
                        acpi_os_printf (" Off %.3X Len %.2X Acc %.2hd\n",
-                                       (obj_desc->common_field.base_byte_offset * 8)
-                                               + obj_desc->common_field.start_field_bit_offset,
-                                       obj_desc->common_field.bit_length,
-                                       obj_desc->common_field.access_byte_width);
+                               (obj_desc->common_field.base_byte_offset * 8)
+                                       + obj_desc->common_field.start_field_bit_offset,
+                               obj_desc->common_field.bit_length,
+                               obj_desc->common_field.access_byte_width);
                        break;
 
                default:
@@ -471,12 +472,13 @@ acpi_ns_dump_one_object (
                        obj_type = ACPI_GET_OBJECT_TYPE (obj_desc);
 
                        if (obj_type > ACPI_TYPE_LOCAL_MAX) {
-                               acpi_os_printf ("(Ptr to ACPI Object type %X [UNKNOWN])\n", obj_type);
+                               acpi_os_printf ("(Ptr to ACPI Object type %X [UNKNOWN])\n",
+                                       obj_type);
                                bytes_to_dump = 32;
                        }
                        else {
                                acpi_os_printf ("(Ptr to ACPI Object type %s, %X)\n",
-                                                  acpi_ut_get_type_name (obj_type), obj_type);
+                                       acpi_ut_get_type_name (obj_type), obj_type);
                                bytes_to_dump = sizeof (union acpi_operand_object);
                        }
                        break;
@@ -484,8 +486,9 @@ acpi_ns_dump_one_object (
 
                default:
 
-                       acpi_os_printf ("(String or Buffer ptr - not an object descriptor) [%s]\n",
-                                       acpi_ut_get_descriptor_name (obj_desc));
+                       acpi_os_printf (
+                               "(String or Buffer ptr - not an object descriptor) [%s]\n",
+                               acpi_ut_get_descriptor_name (obj_desc));
                        bytes_to_dump = 16;
                        break;
                }
@@ -547,12 +550,14 @@ cleanup:
 }
 
 
+#ifdef ACPI_FUTURE_USAGE
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_dump_objects
  *
  * PARAMETERS:  Type                - Object type to be dumped
- *              max_depth           - Maximum depth of dump.  Use ACPI_UINT32_MAX
+ *              max_depth           - Maximum depth of dump. Use ACPI_UINT32_MAX
  *                                    for an effectively unlimited depth.
  *              owner_id            - Dump only objects owned by this ID.  Use
  *                                    ACPI_UINT32_MAX to match all owners.
@@ -632,6 +637,8 @@ acpi_ns_dump_tables (
        return_VOID;
 }
 
+#endif  /*  ACPI_FUTURE_USAGE  */
+
 
 /*******************************************************************************
  *
index 418f03e..d2e1a28 100644 (file)
  *
  * FUNCTION:    acpi_ns_evaluate_relative
  *
- * PARAMETERS:  Handle              - The relative containing object
- *              Pathname            - Name of method to execute, If NULL, the
+ * PARAMETERS:  Pathname            - Name of method to execute, If NULL, the
  *                                    handle is the object to execute
- *              Params              - List of parameters to pass to the method,
- *                                    terminated by NULL.  Params itself may be
- *                                    NULL if no parameters are being passed.
- *              return_object       - Where to put method's return value (if
- *                                    any).  If NULL, no value is returned.
+ *              Info                - Method info block
  *
  * RETURN:      Status
  *
@@ -138,8 +133,7 @@ acpi_ns_evaluate_relative (
        }
 
        /*
-        * Now that we have a handle to the object, we can attempt
-        * to evaluate it.
+        * Now that we have a handle to the object, we can attempt to evaluate it.
         */
        ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n",
                pathname, node, acpi_ns_get_attached_object (node)));
@@ -165,9 +159,9 @@ cleanup1:
  *
  * PARAMETERS:  Pathname            - Fully qualified pathname to the object
  *              Info                - Contains:
- *              return_object       - Where to put method's return value (if
+ *                  return_object   - Where to put method's return value (if
  *                                    any).  If NULL, no value is returned.
- *              Params              - List of parameters to pass to the method,
+ *                  Params          - List of parameters to pass to the method,
  *                                    terminated by NULL.  Params itself may be
  *                                    NULL if no parameters are being passed.
  *
@@ -213,14 +207,14 @@ acpi_ns_evaluate_by_name (
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
 
        if (ACPI_FAILURE (status)) {
-               ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Object at [%s] was not found, status=%.4X\n",
+               ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+                       "Object at [%s] was not found, status=%.4X\n",
                        pathname, status));
                goto cleanup;
        }
 
        /*
-        * Now that we have a handle to the object, we can attempt
-        * to evaluate it.
+        * Now that we have a handle to the object, we can attempt to evaluate it.
         */
        ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n",
                pathname, info->node, acpi_ns_get_attached_object (info->node)));
@@ -303,9 +297,8 @@ acpi_ns_evaluate_by_handle (
        }
 
        /*
-        * For a method alias, we must grab the actual method node
-        * so that proper scoping context will be established
-        * before execution.
+        * For a method alias, we must grab the actual method node so that proper
+        * scoping context will be established before execution.
         */
        if (acpi_ns_get_type (info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
                info->node = ACPI_CAST_PTR (struct acpi_namespace_node, info->node->object);
@@ -314,11 +307,9 @@ acpi_ns_evaluate_by_handle (
        /*
         * Two major cases here:
         * 1) The object is an actual control method -- execute it.
-        * 2) The object is not a method -- just return it's current
-        *      value
+        * 2) The object is not a method -- just return it's current value
         *
-        * In both cases, the namespace is unlocked by the
-        *  acpi_ns* procedure
+        * In both cases, the namespace is unlocked by the acpi_ns* procedure
         */
        if (acpi_ns_get_type (info->node) == ACPI_TYPE_METHOD) {
                /*
@@ -328,15 +319,13 @@ acpi_ns_evaluate_by_handle (
        }
        else {
                /*
-                * Case 2) Object is NOT a method, just return its
-                * current value
+                * Case 2) Object is NOT a method, just return its current value
                 */
                status = acpi_ns_get_object_value (info);
        }
 
        /*
-        * Check if there is a return value on the stack that must
-        * be dealt with
+        * Check if there is a return value on the stack that must be dealt with
         */
        if (status == AE_CTRL_RETURN_VALUE) {
                /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
@@ -345,8 +334,8 @@ acpi_ns_evaluate_by_handle (
        }
 
        /*
-        * Namespace was unlocked by the handling acpi_ns* function,
-        * so we just return
+        * Namespace was unlocked by the handling acpi_ns* function, so we
+        * just return
         */
        return_ACPI_STATUS (status);
 }
@@ -356,12 +345,7 @@ acpi_ns_evaluate_by_handle (
  *
  * FUNCTION:    acpi_ns_execute_control_method
  *
- * PARAMETERS:  method_node         - The method to execute
- *              Params              - List of parameters to pass to the method,
- *                                    terminated by NULL.  Params itself may be
- *                                    NULL if no parameters are being passed.
- *              return_obj_desc     - List of result objects to be returned
- *                                    from the method.
+ * PARAMETERS:  Info            - Method info block (w/params)
  *
  * RETURN:      Status
  *
@@ -430,8 +414,7 @@ acpi_ns_execute_control_method (
  *
  * FUNCTION:    acpi_ns_get_object_value
  *
- * PARAMETERS:  Node                - The object
- *              return_obj_desc     - Where the objects value is returned
+ * PARAMETERS:  Info            - Method info block (w/params)
  *
  * RETURN:      Status
  *
@@ -453,28 +436,25 @@ acpi_ns_get_object_value (
 
 
        /*
-        * Objects require additional resolution steps (e.g., the
-        * Node may be a field that must be read, etc.) -- we can't just grab
-        * the object out of the node.
+        * Objects require additional resolution steps (e.g., the Node may be a
+        * field that must be read, etc.) -- we can't just grab the object out of
+        * the node.
         */
 
        /*
-        * Use resolve_node_to_value() to get the associated value. This call
-        * always deletes obj_desc (allocated above).
+        * Use resolve_node_to_value() to get the associated value. This call always
+        * deletes obj_desc (allocated above).
         *
-        * NOTE: we can get away with passing in NULL for a walk state
-        * because obj_desc is guaranteed to not be a reference to either
-        * a method local or a method argument (because this interface can only be
-        * called from the acpi_evaluate external interface, never called from
-        * a running control method.)
+        * NOTE: we can get away with passing in NULL for a walk state because
+        * obj_desc is guaranteed to not be a reference to either a method local or
+        * a method argument (because this interface can only be called from the
+        * acpi_evaluate external interface, never called from a running method.)
         *
-        * Even though we do not directly invoke the interpreter
-        * for this, we must enter it because we could access an opregion.
-        * The opregion access code assumes that the interpreter
-        * is locked.
+        * Even though we do not directly invoke the interpreter for this, we must
+        * enter it because we could access an opregion. The opregion access code
+        * assumes that the interpreter is locked.
         *
-        * We must release the namespace lock before entering the
-        * intepreter.
+        * We must release the namespace lock before entering the intepreter.
         */
        status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        if (ACPI_FAILURE (status)) {
@@ -485,16 +465,18 @@ acpi_ns_get_object_value (
        if (ACPI_SUCCESS (status)) {
                status = acpi_ex_resolve_node_to_value (&resolved_node, NULL);
                /*
-                * If acpi_ex_resolve_node_to_value() succeeded, the return value was
-                * placed in resolved_node.
+                * If acpi_ex_resolve_node_to_value() succeeded, the return value was placed
+                * in resolved_node.
                 */
                acpi_ex_exit_interpreter ();
 
                if (ACPI_SUCCESS (status)) {
                        status = AE_CTRL_RETURN_VALUE;
-                       info->return_object = ACPI_CAST_PTR (union acpi_operand_object, resolved_node);
+                       info->return_object = ACPI_CAST_PTR
+                                        (union acpi_operand_object, resolved_node);
                        ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n",
-                               info->return_object, acpi_ut_get_object_type_name (info->return_object)));
+                               info->return_object,
+                               acpi_ut_get_object_type_name (info->return_object)));
                }
        }
 
index 8617875..c6518f8 100644 (file)
@@ -77,7 +77,8 @@ acpi_ns_initialize_objects (
 
        ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
                "**** Starting initialization of namespace objects ****\n"));
-       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "Completing Region/Field/Buffer/Package initialization:"));
+       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
+               "Completing Region/Field/Buffer/Package initialization:"));
 
        /* Set all init info to zero */
 
@@ -142,7 +143,8 @@ acpi_ns_initialize_devices (
        info.num_STA = 0;
        info.num_INI = 0;
 
-       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "Executing all Device _STA and_INI methods:"));
+       ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
+               "Executing all Device _STA and_INI methods:"));
 
        status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
        if (ACPI_FAILURE (status)) {
@@ -257,8 +259,8 @@ acpi_ns_init_one_object (
        }
 
        /*
-        * Each of these types can contain executable AML code within
-        * the declaration.
+        * Each of these types can contain executable AML code within the
+        * declaration.
         */
        switch (type) {
        case ACPI_TYPE_REGION:
@@ -267,21 +269,18 @@ acpi_ns_init_one_object (
                status = acpi_ds_get_region_arguments (obj_desc);
                break;
 
-
        case ACPI_TYPE_BUFFER_FIELD:
 
                info->field_init++;
                status = acpi_ds_get_buffer_field_arguments (obj_desc);
                break;
 
-
        case ACPI_TYPE_BUFFER:
 
                info->buffer_init++;
                status = acpi_ds_get_buffer_arguments (obj_desc);
                break;
 
-
        case ACPI_TYPE_PACKAGE:
 
                info->package_init++;
@@ -301,15 +300,17 @@ acpi_ns_init_one_object (
                                acpi_format_exception (status)));
        }
 
-       /* Print a dot for each object unless we are going to print the entire pathname */
-
+       /*
+        * Print a dot for each object unless we are going to print the entire
+        * pathname
+        */
        if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
                ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
        }
 
        /*
-        * We ignore errors from above, and always return OK, since
-        * we don't want to abort the walk on any single error.
+        * We ignore errors from above, and always return OK, since we don't want
+        * to abort the walk on any single error.
         */
        acpi_ex_exit_interpreter ();
        return (AE_OK);
@@ -363,7 +364,8 @@ acpi_ns_init_one_device (
                return_ACPI_STATUS (AE_OK);
        }
 
-       if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && (!(acpi_dbg_level & ACPI_LV_INFO))) {
+       if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) &&
+               (!(acpi_dbg_level & ACPI_LV_INFO))) {
                ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
        }
 
@@ -429,6 +431,5 @@ acpi_ns_init_one_device (
                status = acpi_gbl_init_handler (pinfo.node, ACPI_INIT_DEVICE_INI);
        }
 
-
        return_ACPI_STATUS (status);
 }
index e0b9663..4316ea6 100644 (file)
@@ -202,7 +202,11 @@ acpi_ns_get_pathname_length (
                next_node = acpi_ns_get_parent_node (next_node);
        }
 
-       return (size + 1);
+       if (!size) {
+               size = 1;       /* Root node case */
+       }
+
+       return (size + 1);  /* +1 for null string terminator */
 }
 
 
@@ -253,7 +257,8 @@ acpi_ns_handle_to_pathname (
 
        acpi_ns_build_external_path (node, required_size, buffer->pointer);
 
-       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s [%X] \n", (char *) buffer->pointer, (u32) required_size));
+       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s [%X] \n",
+               (char *) buffer->pointer, (u32) required_size));
        return_ACPI_STATUS (AE_OK);
 }
 
index 7870a43..0edc5e2 100644 (file)
@@ -96,8 +96,10 @@ acpi_ns_search_node (
 
                scope_name = acpi_ns_get_external_pathname (node);
                if (scope_name) {
-                       ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching %s (%p) For [%4.4s] (%s)\n",
-                               scope_name, node, (char *) &target_name, acpi_ut_get_type_name (type)));
+                       ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+                               "Searching %s (%p) For [%4.4s] (%s)\n",
+                               scope_name, node, (char *) &target_name,
+                               acpi_ut_get_type_name (type)));
 
                        ACPI_MEM_FREE (scope_name);
                }
@@ -164,7 +166,7 @@ acpi_ns_search_node (
  * PARAMETERS:  *target_name        - Ascii ACPI name to search for
  *              *Node               - Starting node where search will begin
  *              Type                - Object type to match
- *              **return_node       - Where the matched Named Obj is returned
+ *              **return_node       - Where the matched Node is returned
  *
  * RETURN:      Status
  *
@@ -199,13 +201,13 @@ acpi_ns_search_parent_tree (
        parent_node = acpi_ns_get_parent_node (node);
 
        /*
-        * If there is no parent (i.e., we are at the root) or
-        * type is "local", we won't be searching the parent tree.
+        * If there is no parent (i.e., we are at the root) or type is "local",
+        * we won't be searching the parent tree.
         */
        if (!parent_node) {
                ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] has no parent\n",
                        (char *) &target_name));
-                return_ACPI_STATUS (AE_NOT_FOUND);
+               return_ACPI_STATUS (AE_NOT_FOUND);
        }
 
        if (acpi_ns_local (type)) {
@@ -217,11 +219,12 @@ acpi_ns_search_parent_tree (
 
        /* Search the parent tree */
 
-       ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching parent for %4.4s\n", (char *) &target_name));
+       ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+               "Searching parent [%4.4s] for [%4.4s]\n",
+               acpi_ut_get_node_name (parent_node), (char *) &target_name));
 
        /*
-        * Search parents until found the target or we have backed up to
-        * the root
+        * Search parents until target is found or we have backed up to the root
         */
        while (parent_node) {
                /*
@@ -230,7 +233,7 @@ acpi_ns_search_parent_tree (
                 * the actual name we are searching for.  Typechecking comes later.
                 */
                status = acpi_ns_search_node (target_name, parent_node,
-                                  ACPI_TYPE_ANY, return_node);
+                                 ACPI_TYPE_ANY, return_node);
                if (ACPI_SUCCESS (status)) {
                        return_ACPI_STATUS (status);
                }
@@ -293,7 +296,8 @@ acpi_ns_search_and_enter (
        /* Parameter validation */
 
        if (!node || !target_name || !return_node) {
-               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null param: Node %p Name %X return_node %p\n",
+               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+                       "Null param: Node %p Name %X return_node %p\n",
                        node, target_name, return_node));
 
                ACPI_REPORT_ERROR (("ns_search_and_enter: Null parameter\n"));
@@ -330,22 +334,20 @@ acpi_ns_search_and_enter (
        }
 
        /*
-        * The name was not found.  If we are NOT performing the
-        * first pass (name entry) of loading the namespace, search
-        * the parent tree (all the way to the root if necessary.)
-        * We don't want to perform the parent search when the
-        * namespace is actually being loaded.  We want to perform
-        * the search when namespace references are being resolved
-        * (load pass 2) and during the execution phase.
+        * The name was not found.  If we are NOT performing the first pass
+        * (name entry) of loading the namespace, search the parent tree (all the
+        * way to the root if necessary.) We don't want to perform the parent
+        * search when the namespace is actually being loaded.  We want to perform
+        * the search when namespace references are being resolved (load pass 2)
+        * and during the execution phase.
         */
        if ((interpreter_mode != ACPI_IMODE_LOAD_PASS1) &&
                (flags & ACPI_NS_SEARCH_PARENT)) {
                /*
-                * Not found at this level - search parent tree according
-                * to ACPI specification
+                * Not found at this level - search parent tree according to the
+                * ACPI specification
                 */
-               status = acpi_ns_search_parent_tree (target_name, node,
-                                type, return_node);
+               status = acpi_ns_search_parent_tree (target_name, node, type, return_node);
                if (ACPI_SUCCESS (status)) {
                        return_ACPI_STATUS (status);
                }
@@ -355,7 +357,8 @@ acpi_ns_search_and_enter (
         * In execute mode, just search, never add names.  Exit now.
         */
        if (interpreter_mode == ACPI_IMODE_EXECUTE) {
-               ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%4.4s Not found in %p [Not adding]\n",
+               ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+                       "%4.4s Not found in %p [Not adding]\n",
                        (char *) &target_name, node));
 
                return_ACPI_STATUS (AE_NOT_FOUND);
index bf49ce2..47509cc 100644 (file)
@@ -85,12 +85,14 @@ acpi_ns_report_error (
        if (lookup_status == AE_BAD_CHARACTER) {
                /* There is a non-ascii character in the name */
 
-               acpi_os_printf ("[0x%4.4X] (NON-ASCII)\n", *(ACPI_CAST_PTR (u32, internal_name)));
+               acpi_os_printf ("[0x%4.4X] (NON-ASCII)\n",
+                       *(ACPI_CAST_PTR (u32, internal_name)));
        }
        else {
                /* Convert path to external format */
 
-               status = acpi_ns_externalize_name (ACPI_UINT32_MAX, internal_name, NULL, &name);
+               status = acpi_ns_externalize_name (ACPI_UINT32_MAX,
+                                internal_name, NULL, &name);
 
                /* Print target name */
 
@@ -141,7 +143,8 @@ acpi_ns_report_method_error (
 
 
        if (path) {
-               status = acpi_ns_get_node_by_path (path, prefix_node, ACPI_NS_NO_UPSEARCH, &node);
+               status = acpi_ns_get_node_by_path (path, prefix_node,
+                                ACPI_NS_NO_UPSEARCH, &node);
                if (ACPI_FAILURE (status)) {
                        acpi_os_printf ("report_method_error: Could not get node\n");
                        return;
@@ -180,7 +183,7 @@ acpi_ns_print_node_pathname (
                return;
        }
 
-       /* Convert handle to full pathname and print it (with supplied message) */
+       /* Convert handle to full pathname and print it (with supplied message) */
 
        buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
 
@@ -324,13 +327,11 @@ acpi_ns_get_internal_name_length (
        info->fully_qualified = FALSE;
 
        /*
-        * For the internal name, the required length is 4 bytes
-        * per segment, plus 1 each for root_prefix, multi_name_prefix_op,
-        * segment count, trailing null (which is not really needed,
-        * but no there's harm in putting it there)
+        * For the internal name, the required length is 4 bytes per segment, plus
+        * 1 each for root_prefix, multi_name_prefix_op, segment count, trailing null
+        * (which is not really needed, but no there's harm in putting it there)
         *
-        * strlen() + 1 covers the first name_seg, which has no
-        * path separator
+        * strlen() + 1 covers the first name_seg, which has no path separator
         */
        if (acpi_ns_valid_root_prefix (next_external_char[0])) {
                info->fully_qualified = TRUE;
@@ -347,10 +348,9 @@ acpi_ns_get_internal_name_length (
        }
 
        /*
-        * Determine the number of ACPI name "segments" by counting
-        * the number of path separators within the string.  Start
-        * with one segment since the segment count is (# separators)
-        * + 1, and zero separators is ok.
+        * Determine the number of ACPI name "segments" by counting the number of
+        * path separators within the string. Start with one segment since the
+        * segment count is [(# separators) + 1], and zero separators is ok.
         */
        if (*next_external_char) {
                info->num_segments = 1;
@@ -625,7 +625,8 @@ acpi_ns_externalize_name (
                        /* <count> 4-byte names */
 
                        names_index = prefix_length + 2;
-                       num_segments = (acpi_native_uint) (u8) internal_name[(acpi_native_uint) (prefix_length + 1)];
+                       num_segments = (acpi_native_uint) (u8)
+                                          internal_name[(acpi_native_uint) (prefix_length + 1)];
                        break;
 
                case AML_DUAL_NAME_PREFIX:
@@ -672,7 +673,7 @@ acpi_ns_externalize_name (
        }
 
        /*
-        * Build converted_name...
+        * Build converted_name
         */
        *converted_name = ACPI_MEM_CALLOCATE (required_length);
        if (!(*converted_name)) {
@@ -756,7 +757,7 @@ acpi_ns_map_handle_to_node (
  *
  * PARAMETERS:  Node          - Node to be converted to a Handle
  *
- * RETURN:      An USER acpi_handle
+ * RETURN:      A user handle
  *
  * DESCRIPTION: Convert a real Node to a namespace handle
  *
@@ -960,7 +961,7 @@ cleanup:
  *              (which "should not happen").
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_name
 acpi_ns_find_parent_name (
        struct acpi_namespace_node      *child_node)
@@ -976,7 +977,8 @@ acpi_ns_find_parent_name (
 
                parent_node = acpi_ns_get_parent_node (child_node);
                if (parent_node) {
-                       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Parent of %p [%4.4s] is %p [%4.4s]\n",
+                       ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+                               "Parent of %p [%4.4s] is %p [%4.4s]\n",
                                child_node, acpi_ut_get_node_name (child_node),
                                parent_node, acpi_ut_get_node_name (parent_node)));
 
@@ -985,12 +987,14 @@ acpi_ns_find_parent_name (
                        }
                }
 
-               ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "unable to find parent of %p (%4.4s)\n",
+               ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+                       "Unable to find parent of %p (%4.4s)\n",
                        child_node, acpi_ut_get_node_name (child_node)));
        }
 
        return_VALUE (ACPI_UNKNOWN_NAME);
 }
+#endif
 
 
 /*******************************************************************************
@@ -1018,11 +1022,9 @@ acpi_ns_get_parent_node (
        }
 
        /*
-        * Walk to the end of this peer list.
-        * The last entry is marked with a flag and the peer
-        * pointer is really a pointer back to the parent.
-        * This saves putting a parent back pointer in each and
-        * every named object!
+        * Walk to the end of this peer list. The last entry is marked with a flag
+        * and the peer pointer is really a pointer back to the parent. This saves
+        * putting a parent back pointer in each and every named object!
         */
        while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
                node = node->peer;
@@ -1039,8 +1041,8 @@ acpi_ns_get_parent_node (
  *
  * PARAMETERS:  Node       - Current table entry
  *
- * RETURN:      Next valid Node in the linked node list.  NULL if no more valid
- *              nodess
+ * RETURN:      Next valid Node in the linked node list. NULL if no more valid
+ *              nodes.
  *
  * DESCRIPTION: Find the next valid node within a name table.
  *              Useful for implementing NULL-end-of-list loops.
index 8e916b5..ce55bdf 100644 (file)
@@ -42,6 +42,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
@@ -72,7 +73,7 @@
  *              be valid (non-null)
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_evaluate_object_typed (
        acpi_handle                     handle,
@@ -143,6 +144,7 @@ acpi_evaluate_object_typed (
        return_buffer->length = 0;
        return_ACPI_STATUS (AE_TYPE);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
@@ -354,6 +356,7 @@ acpi_evaluate_object (
 
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_evaluate_object);
 
 
 /*******************************************************************************
@@ -426,6 +429,7 @@ acpi_walk_namespace (
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_walk_namespace);
 
 
 /*******************************************************************************
@@ -599,6 +603,7 @@ acpi_get_devices (
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_get_devices);
 
 
 /*******************************************************************************
index 0508b4d..1e4d9eb 100644 (file)
@@ -42,6 +42,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
@@ -129,6 +130,7 @@ acpi_get_handle (
 
        return (status);
 }
+EXPORT_SYMBOL(acpi_get_handle);
 
 
 /******************************************************************************
@@ -210,6 +212,7 @@ unlock_and_exit:
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return (status);
 }
+EXPORT_SYMBOL(acpi_get_name);
 
 
 /******************************************************************************
@@ -359,4 +362,5 @@ cleanup:
        }
        return (status);
 }
+EXPORT_SYMBOL(acpi_get_object_info);
 
index 5370320..3ed4370 100644 (file)
@@ -42,6 +42,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
@@ -106,6 +107,7 @@ acpi_get_type (
        status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return (status);
 }
+EXPORT_SYMBOL(acpi_get_type);
 
 
 /*******************************************************************************
@@ -171,6 +173,7 @@ unlock_and_exit:
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return (status);
 }
+EXPORT_SYMBOL(acpi_get_parent);
 
 
 /*******************************************************************************
@@ -255,5 +258,5 @@ unlock_and_exit:
        (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
        return (status);
 }
-
+EXPORT_SYMBOL(acpi_get_next_object);
 
index 3062037..6025b75 100644 (file)
 #define ARGP_STRING_OP                  ARGP_LIST1 (ARGP_CHARLIST)
 #define ARGP_SUBTRACT_OP                ARGP_LIST3 (ARGP_TERMARG,    ARGP_TERMARG,       ARGP_TARGET)
 #define ARGP_THERMAL_ZONE_OP            ARGP_LIST3 (ARGP_PKGLENGTH,  ARGP_NAME,          ARGP_OBJLIST)
+#define ARGP_TIMER_OP                   ARG_NONE
 #define ARGP_TO_BCD_OP                  ARGP_LIST2 (ARGP_TERMARG,    ARGP_TARGET)
 #define ARGP_TO_BUFFER_OP               ARGP_LIST2 (ARGP_TERMARG,    ARGP_TARGET)
 #define ARGP_TO_DEC_STR_OP              ARGP_LIST2 (ARGP_TERMARG,    ARGP_TARGET)
 #define ARGI_SHIFT_LEFT_OP              ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_SHIFT_RIGHT_OP             ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_SIGNAL_OP                  ARGI_LIST1 (ARGI_EVENT)
-#define ARGI_SIZE_OF_OP                 ARGI_LIST1 (ARGI_DATAOBJECT)
+#define ARGI_SIZE_OF_OP                 ARGI_LIST1 (ARGI_REFERENCE) /* Force delay of operand resolution */
 #define ARGI_SLEEP_OP                   ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_STALL_OP                   ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_STATICSTRING_OP            ARGI_INVALID_OPCODE
 #define ARGI_STRING_OP                  ARGI_INVALID_OPCODE
 #define ARGI_SUBTRACT_OP                ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_THERMAL_ZONE_OP            ARGI_INVALID_OPCODE
+#define ARGI_TIMER_OP                   ARG_NONE
 #define ARGI_TO_BCD_OP                  ARGI_LIST2 (ARGI_INTEGER,    ARGI_FIXED_TARGET)
 #define ARGI_TO_BUFFER_OP               ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
 #define ARGI_TO_DEC_STR_OP              ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
 #define ARGI_TO_HEX_STR_OP              ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
 #define ARGI_TO_INTEGER_OP              ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
 #define ARGI_TO_STRING_OP               ARGI_LIST3 (ARGI_BUFFER,     ARGI_INTEGER,       ARGI_FIXED_TARGET)
-#define ARGI_TYPE_OP                    ARGI_LIST1 (ARGI_ANYTYPE)
+#define ARGI_TYPE_OP                    ARGI_LIST1 (ARGI_REFERENCE) /* Force delay of operand resolution */
 #define ARGI_UNLOAD_OP                  ARGI_LIST1 (ARGI_DDBHANDLE)
 #define ARGI_VAR_PACKAGE_OP             ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_WAIT_OP                    ARGI_LIST2 (ARGI_EVENT,      ARGI_INTEGER)
@@ -527,8 +529,8 @@ const struct acpi_opcode_info     acpi_gbl_aml_op_info[AML_NUM_OPCODES] =
 /* 35 */ ACPI_OP ("CreateByteField",    ARGP_CREATE_BYTE_FIELD_OP, ARGI_CREATE_BYTE_FIELD_OP,  ACPI_TYPE_BUFFER_FIELD,      AML_CLASS_CREATE,          AML_TYPE_CREATE_FIELD,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
 /* 36 */ ACPI_OP ("CreateBitField",     ARGP_CREATE_BIT_FIELD_OP,  ARGI_CREATE_BIT_FIELD_OP,   ACPI_TYPE_BUFFER_FIELD,      AML_CLASS_CREATE,          AML_TYPE_CREATE_FIELD,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
 /* 37 */ ACPI_OP ("ObjectType",         ARGP_TYPE_OP,              ARGI_TYPE_OP,               ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_1A_0T_1R,   AML_FLAGS_EXEC_1A_0T_1R),
-/* 38 */ ACPI_OP ("LAnd",               ARGP_LAND_OP,              ARGI_LAND_OP,               ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_0T_1R,   AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
-/* 39 */ ACPI_OP ("LOr",                ARGP_LOR_OP,               ARGI_LOR_OP,                ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_0T_1R,   AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+/* 38 */ ACPI_OP ("LAnd",               ARGP_LAND_OP,              ARGI_LAND_OP,               ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_0T_1R,   AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT),
+/* 39 */ ACPI_OP ("LOr",                ARGP_LOR_OP,               ARGI_LOR_OP,                ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_0T_1R,   AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT),
 /* 3A */ ACPI_OP ("LNot",               ARGP_LNOT_OP,              ARGI_LNOT_OP,               ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_1A_0T_1R,   AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
 /* 3B */ ACPI_OP ("LEqual",             ARGP_LEQUAL_OP,            ARGI_LEQUAL_OP,             ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_0T_1R,   AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
 /* 3C */ ACPI_OP ("LGreater",           ARGP_LGREATER_OP,          ARGI_LGREATER_OP,           ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_0T_1R,   AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
@@ -588,7 +590,6 @@ const struct acpi_opcode_info     acpi_gbl_aml_op_info[AML_NUM_OPCODES] =
 /* 6C */ ACPI_OP ("-ASCII_ONLY-",       ARG_NONE,                  ARG_NONE,                   ACPI_TYPE_ANY,               AML_CLASS_ASCII,           AML_TYPE_BOGUS,           AML_HAS_ARGS),
 /* 6D */ ACPI_OP ("-PREFIX_ONLY-",      ARG_NONE,                  ARG_NONE,                   ACPI_TYPE_ANY,               AML_CLASS_PREFIX,          AML_TYPE_BOGUS,           AML_HAS_ARGS),
 
-
 /* ACPI 2.0 opcodes */
 
 /* 6E */ ACPI_OP ("QwordConst",         ARGP_QWORD_OP,             ARGI_QWORD_OP,              ACPI_TYPE_INTEGER,           AML_CLASS_ARGUMENT,        AML_TYPE_LITERAL,         AML_CONSTANT),
@@ -606,7 +607,11 @@ const struct acpi_opcode_info     acpi_gbl_aml_op_info[AML_NUM_OPCODES] =
 /* 7A */ ACPI_OP ("Continue",           ARGP_CONTINUE_OP,          ARGI_CONTINUE_OP,           ACPI_TYPE_ANY,               AML_CLASS_CONTROL,         AML_TYPE_CONTROL,         0),
 /* 7B */ ACPI_OP ("LoadTable",          ARGP_LOAD_TABLE_OP,        ARGI_LOAD_TABLE_OP,         ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_6A_0T_1R,   AML_FLAGS_EXEC_6A_0T_1R),
 /* 7C */ ACPI_OP ("DataTableRegion",    ARGP_DATA_REGION_OP,       ARGI_DATA_REGION_OP,        ACPI_TYPE_REGION,            AML_CLASS_NAMED_OBJECT,    AML_TYPE_NAMED_SIMPLE,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
-/* 7D */ ACPI_OP ("[EvalSubTree]",      ARGP_SCOPE_OP,             ARGI_SCOPE_OP,              ACPI_TYPE_ANY,               AML_CLASS_NAMED_OBJECT,    AML_TYPE_NAMED_NO_OBJ,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE)
+/* 7D */ ACPI_OP ("[EvalSubTree]",      ARGP_SCOPE_OP,             ARGI_SCOPE_OP,              ACPI_TYPE_ANY,               AML_CLASS_NAMED_OBJECT,    AML_TYPE_NAMED_NO_OBJ,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE),
+
+/* ACPI 3.0 opcodes */
+
+/* 7E */ ACPI_OP ("Timer",              ARGP_TIMER_OP,             ARGI_TIMER_OP,              ACPI_TYPE_ANY,               AML_CLASS_EXECUTE,         AML_TYPE_EXEC_0A_0T_1R,   AML_FLAGS_EXEC_0A_0T_1R)
 
 /*! [End] no source code translation !*/
 };
@@ -615,7 +620,6 @@ const struct acpi_opcode_info     acpi_gbl_aml_op_info[AML_NUM_OPCODES] =
  * This table is directly indexed by the opcodes, and returns an
  * index into the table above
  */
-
 static const u8 acpi_gbl_short_op_index[256] =
 {
 /*              0     1     2     3     4     5     6     7  */
@@ -654,7 +658,10 @@ static const u8 acpi_gbl_short_op_index[256] =
 /* 0xF8 */     _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45,
 };
 
-
+/*
+ * This table is indexed by the second opcode of the extended opcode
+ * pair.  It returns an index into the opcode table (acpi_gbl_aml_op_info)
+ */
 static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] =
 {
 /*              0     1     2     3     4     5     6     7  */
@@ -665,7 +672,7 @@ static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] =
 /* 0x18 */     _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B,
 /* 0x20 */     0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
 /* 0x28 */     0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x30 */     0x55, 0x56, 0x57, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x30 */     0x55, 0x56, 0x57, 0x7e, _UNK, _UNK, _UNK, _UNK,
 /* 0x38 */     _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
 /* 0x40 */     _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
 /* 0x48 */     _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
@@ -724,7 +731,7 @@ acpi_ps_get_opcode_info (
 
        default:
 
-               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown extended opcode [%X]\n", opcode));
+               ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown AML opcode [%4.4X]\n", opcode));
                break;
        }
 
index 00a3540..8c588dc 100644 (file)
@@ -164,123 +164,125 @@ acpi_ps_complete_this_op (
 
        /* Delete this op and the subtree below it if asked to */
 
-       if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) == ACPI_PARSE_DELETE_TREE) &&
-               (walk_state->op_info->class != AML_CLASS_ARGUMENT)) {
-               /* Make sure that we only delete this subtree */
+       if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) ||
+                (walk_state->op_info->class == AML_CLASS_ARGUMENT)) {
+               return_VOID;
+       }
+
+       /* Make sure that we only delete this subtree */
+
+       if (op->common.parent) {
+               /*
+                * Check if we need to replace the operator and its subtree
+                * with a return value op (placeholder op)
+                */
+               parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode);
+
+               switch (parent_info->class) {
+               case AML_CLASS_CONTROL:
+                       break;
+
+               case AML_CLASS_CREATE:
 
-               if (op->common.parent) {
                        /*
-                        * Check if we need to replace the operator and its subtree
-                        * with a return value op (placeholder op)
+                        * These opcodes contain term_arg operands. The current
+                        * op must be replaced by a placeholder return op
                         */
-                       parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode);
-
-                       switch (parent_info->class) {
-                       case AML_CLASS_CONTROL:
-                               break;
+                       replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
+                       if (!replacement_op) {
+                               goto cleanup;
+                       }
+                       break;
 
-                       case AML_CLASS_CREATE:
+               case AML_CLASS_NAMED_OBJECT:
 
-                               /*
-                                * These opcodes contain term_arg operands. The current
-                                * op must be replaced by a placeholder return op
-                                */
+                       /*
+                        * These opcodes contain term_arg operands. The current
+                        * op must be replaced by a placeholder return op
+                        */
+                       if ((op->common.parent->common.aml_opcode == AML_REGION_OP)      ||
+                               (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) ||
+                               (op->common.parent->common.aml_opcode == AML_BUFFER_OP)      ||
+                               (op->common.parent->common.aml_opcode == AML_PACKAGE_OP)     ||
+                               (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
                                replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
                                if (!replacement_op) {
-                                       return_VOID;
+                                       goto cleanup;
                                }
-                               break;
-
-                       case AML_CLASS_NAMED_OBJECT:
+                       }
 
-                               /*
-                                * These opcodes contain term_arg operands. The current
-                                * op must be replaced by a placeholder return op
-                                */
-                               if ((op->common.parent->common.aml_opcode == AML_REGION_OP)      ||
-                                       (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) ||
-                                       (op->common.parent->common.aml_opcode == AML_BUFFER_OP)      ||
-                                       (op->common.parent->common.aml_opcode == AML_PACKAGE_OP)     ||
-                                       (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
-                                       replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
+                       if ((op->common.parent->common.aml_opcode == AML_NAME_OP) &&
+                               (walk_state->descending_callback != acpi_ds_exec_begin_op)) {
+                               if ((op->common.aml_opcode == AML_BUFFER_OP) ||
+                                       (op->common.aml_opcode == AML_PACKAGE_OP) ||
+                                       (op->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
+                                       replacement_op = acpi_ps_alloc_op (op->common.aml_opcode);
                                        if (!replacement_op) {
-                                               return_VOID;
+                                               goto cleanup;
                                        }
+
+                                       replacement_op->named.data = op->named.data;
+                                       replacement_op->named.length = op->named.length;
                                }
+                       }
+                       break;
 
-                               if ((op->common.parent->common.aml_opcode == AML_NAME_OP) &&
-                                       (walk_state->descending_callback != acpi_ds_exec_begin_op)) {
-                                       if ((op->common.aml_opcode == AML_BUFFER_OP) ||
-                                               (op->common.aml_opcode == AML_PACKAGE_OP) ||
-                                               (op->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
-                                               replacement_op = acpi_ps_alloc_op (op->common.aml_opcode);
-                                               if (!replacement_op) {
-                                                       return_VOID;
-                                               }
+               default:
+                       replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
+                       if (!replacement_op) {
+                               goto cleanup;
+                       }
+               }
 
-                                               replacement_op->named.data = op->named.data;
-                                               replacement_op->named.length = op->named.length;
-                                       }
-                               }
-                               break;
+               /* We must unlink this op from the parent tree */
 
-                       default:
-                               replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
-                               if (!replacement_op) {
-                                       return_VOID;
-                               }
+               prev = op->common.parent->common.value.arg;
+               if (prev == op) {
+                       /* This op is the first in the list */
+
+                       if (replacement_op) {
+                               replacement_op->common.parent       = op->common.parent;
+                               replacement_op->common.value.arg    = NULL;
+                               replacement_op->common.node         = op->common.node;
+                               op->common.parent->common.value.arg = replacement_op;
+                               replacement_op->common.next         = op->common.next;
+                       }
+                       else {
+                               op->common.parent->common.value.arg = op->common.next;
                        }
+               }
 
-                       /* We must unlink this op from the parent tree */
+               /* Search the parent list */
 
-                       prev = op->common.parent->common.value.arg;
-                       if (prev == op) {
-                               /* This op is the first in the list */
+               else while (prev) {
+                       /* Traverse all siblings in the parent's argument list */
 
+                       next = prev->common.next;
+                       if (next == op) {
                                if (replacement_op) {
-                                       replacement_op->common.parent       = op->common.parent;
-                                       replacement_op->common.value.arg    = NULL;
-                                       replacement_op->common.node         = op->common.node;
-                                       op->common.parent->common.value.arg = replacement_op;
-                                       replacement_op->common.next         = op->common.next;
+                                       replacement_op->common.parent   = op->common.parent;
+                                       replacement_op->common.value.arg = NULL;
+                                       replacement_op->common.node     = op->common.node;
+                                       prev->common.next               = replacement_op;
+                                       replacement_op->common.next     = op->common.next;
+                                       next = NULL;
                                }
                                else {
-                                       op->common.parent->common.value.arg    = op->common.next;
+                                       prev->common.next = op->common.next;
+                                       next = NULL;
                                }
                        }
 
-                       /* Search the parent list */
-
-                       else while (prev) {
-                               /* Traverse all siblings in the parent's argument list */
-
-                               next = prev->common.next;
-                               if (next == op) {
-                                       if (replacement_op) {
-                                               replacement_op->common.parent   = op->common.parent;
-                                               replacement_op->common.value.arg = NULL;
-                                               replacement_op->common.node     = op->common.node;
-                                               prev->common.next               = replacement_op;
-                                               replacement_op->common.next     = op->common.next;
-                                               next = NULL;
-                                       }
-                                       else {
-                                               prev->common.next = op->common.next;
-                                               next = NULL;
-                                       }
-                               }
-
-                               prev = next;
-                       }
+                       prev = next;
                }
+       }
 
-               /* Now we can actually delete the subtree rooted at op */
 
-               acpi_ps_delete_parse_tree (op);
+cleanup:
 
-               return_VOID;
-       }
+       /* Now we can actually delete the subtree rooted at op */
 
+       acpi_ps_delete_parse_tree (op);
        return_VOID;
 }
 
@@ -552,7 +554,8 @@ acpi_ps_parse_loop (
                                if (!pre_op) {
                                        pre_op = acpi_ps_alloc_op (walk_state->opcode);
                                        if (!pre_op) {
-                                               return_ACPI_STATUS (AE_NO_MEMORY);
+                                               status = AE_NO_MEMORY;
+                                               goto close_this_op;
                                        }
                                }
 
@@ -578,7 +581,8 @@ acpi_ps_parse_loop (
                                /* Make sure that we found a NAME and didn't run out of arguments */
 
                                if (!GET_CURRENT_ARG_TYPE (walk_state->arg_types)) {
-                                       return_ACPI_STATUS (AE_AML_NO_OPERAND);
+                                       status = AE_AML_NO_OPERAND;
+                                       goto close_this_op;
                                }
 
                                /* We know that this arg is a name, move to next arg */
@@ -638,7 +642,8 @@ acpi_ps_parse_loop (
                                walk_state->op_info = acpi_ps_get_opcode_info (walk_state->opcode);
                                op = acpi_ps_alloc_op (walk_state->opcode);
                                if (!op) {
-                                       return_ACPI_STATUS (AE_NO_MEMORY);
+                                       status = AE_NO_MEMORY;
+                                       goto close_this_op;
                                }
 
                                if (walk_state->op_info->flags & AML_CREATE) {
@@ -801,7 +806,7 @@ acpi_ps_parse_loop (
                        status = acpi_ps_push_scope (parser_state, op,
                                         walk_state->arg_types, walk_state->arg_count);
                        if (ACPI_FAILURE (status)) {
-                               return_ACPI_STATUS (status);
+                               goto close_this_op;
                        }
                        op = NULL;
                        continue;
@@ -1128,7 +1133,7 @@ acpi_ps_parse_aml (
                else if (status == AE_CTRL_TERMINATE) {
                        status = AE_OK;
                }
-               else if (status != AE_OK) {
+               else if ((status != AE_OK) && (walk_state->method_desc)) {
                        ACPI_REPORT_METHOD_ERROR ("Method execution failed",
                                walk_state->method_node, NULL, status);
 
index a25f31c..15e7ec1 100644 (file)
@@ -181,6 +181,8 @@ acpi_ps_append_arg (
 }
 
 
+#ifdef ACPI_FUTURE_USAGE
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ps_get_child
@@ -192,7 +194,6 @@ acpi_ps_append_arg (
  * DESCRIPTION: Get op's children or NULL if none
  *
  ******************************************************************************/
-
 union acpi_parse_object *
 acpi_ps_get_child (
        union acpi_parse_object         *op)
@@ -322,4 +323,5 @@ acpi_ps_get_depth_next (
        return (next);
 }
 
+#endif  /*  ACPI_FUTURE_USAGE  */
 
index e4b8a28..148b8f4 100644 (file)
@@ -129,10 +129,9 @@ union acpi_parse_object*
 acpi_ps_alloc_op (
        u16                             opcode)
 {
-       union acpi_parse_object         *op = NULL;
-       u32                             size;
-       u8                              flags;
+       union acpi_parse_object         *op;
        const struct acpi_opcode_info   *op_info;
+       u8                              flags = ACPI_PARSEOP_GENERIC;
 
 
        ACPI_FUNCTION_ENTRY ();
@@ -140,32 +139,28 @@ acpi_ps_alloc_op (
 
        op_info = acpi_ps_get_opcode_info (opcode);
 
-       /* Allocate the minimum required size object */
+       /* Determine type of parse_op required */
 
        if (op_info->flags & AML_DEFER) {
-               size = sizeof (struct acpi_parse_obj_named);
                flags = ACPI_PARSEOP_DEFERRED;
        }
        else if (op_info->flags & AML_NAMED) {
-               size = sizeof (struct acpi_parse_obj_named);
                flags = ACPI_PARSEOP_NAMED;
        }
        else if (opcode == AML_INT_BYTELIST_OP) {
-               size = sizeof (struct acpi_parse_obj_named);
                flags = ACPI_PARSEOP_BYTELIST;
        }
-       else {
-               size = sizeof (struct acpi_parse_obj_common);
-               flags = ACPI_PARSEOP_GENERIC;
-       }
 
-       if (size == sizeof (struct acpi_parse_obj_common)) {
-               /*
-                * The generic op is by far the most common (16 to 1)
-                */
+       /* Allocate the minimum required size object */
+
+       if (flags == ACPI_PARSEOP_GENERIC) {
+               /* The generic op (default) is by far the most common (16 to 1) */
+
                op = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_PSNODE);
        }
        else {
+               /* Extended parseop */
+
                op = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_PSNODE_EXT);
        }
 
@@ -272,6 +267,7 @@ acpi_ps_is_prefix_char (
 /*
  * Get op's name (4-byte name segment) or 0 if unnamed
  */
+#ifdef ACPI_FUTURE_USAGE
 u32
 acpi_ps_get_name (
        union acpi_parse_object         *op)
@@ -288,6 +284,7 @@ acpi_ps_get_name (
 
        return (op->named.name);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*
index ec264c8..ce3f41b 100644 (file)
@@ -67,6 +67,7 @@ acpi_pci_data_handler (
  * to resolve PCI information for ACPI-PCI devices defined in the namespace.
  * This typically occurs when resolving PCI operation region information.
  */
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_os_get_pci_id (
        acpi_handle             handle,
@@ -114,6 +115,7 @@ acpi_os_get_pci_id (
 
        return_ACPI_STATUS(AE_OK);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
        
 int
index 9916b65..2130b74 100644 (file)
@@ -3,6 +3,8 @@
 #
 
 obj-y := rsaddr.o  rscreate.o  rsio.o   rslist.o    rsmisc.o   rsxface.o \
-        rscalc.o  rsdump.o    rsirq.o  rsmemory.o  rsutils.o
+        rscalc.o  rsirq.o  rsmemory.o  rsutils.o
+
+obj-$(ACPI_FUTURE_USAGE) += rsdump.o
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
index 299fc93..3622852 100644 (file)
@@ -74,7 +74,6 @@ acpi_rs_get_byte_stream_length (
 {
        acpi_size                       byte_stream_size_needed = 0;
        acpi_size                       segment_size;
-       struct acpi_resource_ext_irq    *ex_irq = NULL;
        u8                              done = FALSE;
 
 
@@ -91,8 +90,8 @@ acpi_rs_get_byte_stream_length (
                case ACPI_RSTYPE_IRQ:
                        /*
                         * IRQ Resource
-                        * For an IRQ Resource, Byte 3, although optional, will
-                        * always be created - it holds IRQ information.
+                        * For an IRQ Resource, Byte 3, although optional, will always be
+                        * created - it holds IRQ information.
                         */
                        segment_size = 4;
                        break;
@@ -108,8 +107,8 @@ acpi_rs_get_byte_stream_length (
                case ACPI_RSTYPE_START_DPF:
                        /*
                         * Start Dependent Functions Resource
-                        * For a start_dependent_functions Resource, Byte 1,
-                        * although optional, will always be created.
+                        * For a start_dependent_functions Resource, Byte 1, although
+                        * optional, will always be created.
                         */
                        segment_size = 2;
                        break;
@@ -141,10 +140,9 @@ acpi_rs_get_byte_stream_length (
                case ACPI_RSTYPE_VENDOR:
                        /*
                         * Vendor Defined Resource
-                        * For a Vendor Specific resource, if the Length is
-                        * between 1 and 7 it will be created as a Small
-                        * Resource data type, otherwise it is a Large
-                        * Resource data type.
+                        * For a Vendor Specific resource, if the Length is between 1 and 7
+                        * it will be created as a Small Resource data type, otherwise it
+                        * is a Large Resource data type.
                         */
                        if (linked_list->data.vendor_specific.length > 7) {
                                segment_size = 3;
@@ -191,10 +189,9 @@ acpi_rs_get_byte_stream_length (
                case ACPI_RSTYPE_ADDRESS16:
                        /*
                         * 16-Bit Address Resource
-                        * The base size of this byte stream is 16. If a
-                        * Resource Source string is not NULL, add 1 for
-                        * the Index + the length of the null terminated
-                        * string Resource Source + 1 for the null.
+                        * The base size of this byte stream is 16. If a Resource Source
+                        * string is not NULL, add 1 for the Index + the length of the null
+                        * terminated string Resource Source + 1 for the null.
                         */
                        segment_size = 16;
 
@@ -223,10 +220,9 @@ acpi_rs_get_byte_stream_length (
                case ACPI_RSTYPE_ADDRESS64:
                        /*
                         * 64-Bit Address Resource
-                        * The base size of this byte stream is 46. If a Resource
-                        * Source string is not NULL, add 1 for the Index + the
-                        * length of the null terminated string Resource Source +
-                        * 1 for the null.
+                        * The base size of this byte stream is 46. If a resource_source
+                        * string is not NULL, add 1 for the Index + the length of the null
+                        * terminated string Resource Source + 1 for the null.
                         */
                        segment_size = 46;
 
@@ -239,9 +235,8 @@ acpi_rs_get_byte_stream_length (
                case ACPI_RSTYPE_EXT_IRQ:
                        /*
                         * Extended IRQ Resource
-                        * The base size of this byte stream is 9. This is for an
-                        * Interrupt table length of 1.  For each additional
-                        * interrupt, add 4.
+                        * The base size of this byte stream is 9. This is for an Interrupt
+                        * table length of 1.  For each additional interrupt, add 4.
                         * If a Resource Source string is not NULL, add 1 for the
                         * Index + the length of the null terminated string
                         * Resource Source + 1 for the null.
@@ -249,7 +244,7 @@ acpi_rs_get_byte_stream_length (
                        segment_size = 9 +
                                (((acpi_size) linked_list->data.extended_irq.number_of_interrupts - 1) * 4);
 
-                       if (ex_irq && ex_irq->resource_source.string_ptr) {
+                       if (linked_list->data.extended_irq.resource_source.string_ptr) {
                                segment_size += linked_list->data.extended_irq.resource_source.string_length;
                                segment_size++;
                        }
@@ -257,8 +252,7 @@ acpi_rs_get_byte_stream_length (
 
                default:
                        /*
-                        * If we get here, everything is out of sync,
-                        * so exit with an error
+                        * If we get here, everything is out of sync, exit with error
                         */
                        return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
 
@@ -366,7 +360,6 @@ acpi_rs_get_list_length (
                        /*
                         * 32-Bit Memory Range Resource
                         */
-
                        bytes_consumed = 20;
 
                        structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem32);
@@ -395,14 +388,12 @@ acpi_rs_get_list_length (
                        bytes_consumed = temp16 + 3;
 
                        /*
-                        * Resource Source Index and Resource Source are
-                        * optional elements.  Check the length of the
-                        * Bytestream.  If it is greater than 43, that
-                        * means that an Index exists and is followed by
-                        * a null termininated string.  Therefore, set
-                        * the temp variable to the length minus the minimum
-                        * byte stream length plus the byte for the Index to
-                        * determine the size of the NULL terminiated string.
+                        * Resource Source Index and Resource Source are optional elements.
+                        * Check the length of the Bytestream.  If it is greater than 43,
+                        * that means that an Index exists and is followed by a null
+                        * terminated string.  Therefore, set the temp variable to the
+                        * length minus the minimum byte stream length plus the byte for
+                        * the Index to determine the size of the NULL terminated string.
                         */
                        if (43 < temp16) {
                                temp8 = (u8) (temp16 - 44);
@@ -433,14 +424,12 @@ acpi_rs_get_list_length (
                        bytes_consumed = temp16 + 3;
 
                        /*
-                        * Resource Source Index and Resource Source are
-                        * optional elements.  Check the length of the
-                        * Bytestream.  If it is greater than 23, that
-                        * means that an Index exists and is followed by
-                        * a null termininated string.  Therefore, set
-                        * the temp variable to the length minus the minimum
-                        * byte stream length plus the byte for the Index to
-                        * determine the size of the NULL terminiated string.
+                        * Resource Source Index and Resource Source are optional elements.
+                        * Check the length of the Bytestream.  If it is greater than 23,
+                        * that means that an Index exists and is followed by a null
+                        * terminated string.  Therefore, set the temp variable to the
+                        * length minus the minimum byte stream length plus the byte for
+                        * the Index to determine the size of the NULL terminated string.
                         */
                        if (23 < temp16) {
                                temp8 = (u8) (temp16 - 24);
@@ -471,14 +460,12 @@ acpi_rs_get_list_length (
                        bytes_consumed = temp16 + 3;
 
                        /*
-                        * Resource Source Index and Resource Source are
-                        * optional elements.  Check the length of the
-                        * Bytestream.  If it is greater than 13, that
-                        * means that an Index exists and is followed by
-                        * a null termininated string.  Therefore, set
-                        * the temp variable to the length minus the minimum
-                        * byte stream length plus the byte for the Index to
-                        * determine the size of the NULL terminiated string.
+                        * Resource Source Index and Resource Source are optional elements.
+                        * Check the length of the Bytestream.  If it is greater than 13,
+                        * that means that an Index exists and is followed by a null
+                        * terminated string.  Therefore, set the temp variable to the
+                        * length minus the minimum byte stream length plus the byte for
+                        * the Index to determine the size of the NULL terminated string.
                         */
                        if (13 < temp16) {
                                temp8 = (u8) (temp16 - 14);
@@ -509,9 +496,8 @@ acpi_rs_get_list_length (
                        bytes_consumed = temp16 + 3;
 
                        /*
-                        * Point past the length field and the
-                        * Interrupt vector flags to save off the
-                        * Interrupt table length to the Temp8 variable.
+                        * Point past the length field and the Interrupt vector flags to
+                        * save off the Interrupt table length to the Temp8 variable.
                         */
                        buffer += 3;
                        temp8 = *buffer;
@@ -523,14 +509,12 @@ acpi_rs_get_list_length (
                        additional_bytes = (u8) ((temp8 - 1) * 4);
 
                        /*
-                        * Resource Source Index and Resource Source are
-                        * optional elements.  Check the length of the
-                        * Bytestream.  If it is greater than 9, that
-                        * means that an Index exists and is followed by
-                        * a null termininated string.  Therefore, set
-                        * the temp variable to the length minus the minimum
-                        * byte stream length plus the byte for the Index to
-                        * determine the size of the NULL terminiated string.
+                        * Resource Source Index and Resource Source are optional elements.
+                        * Check the length of the Bytestream.  If it is greater than 9,
+                        * that means that an Index exists and is followed by a null
+                        * terminated string.  Therefore, set the temp variable to the
+                        * length minus the minimum byte stream length plus the byte for
+                        * the Index to determine the size of the NULL terminated string.
                         */
                        if (9 + additional_bytes < temp16) {
                                temp8 = (u8) (temp16 - (9 + additional_bytes));
@@ -565,9 +549,8 @@ acpi_rs_get_list_length (
                                bytes_consumed = 3;
                        }
 
-                       /*
-                        * Point past the descriptor
-                        */
+                       /* Point past the descriptor */
+
                        ++buffer;
 
                        /*
@@ -595,9 +578,8 @@ acpi_rs_get_list_length (
                        buffer = byte_stream_buffer;
                        bytes_consumed = 3;
 
-                       /*
-                        * Point past the descriptor
-                        */
+                       /* Point past the descriptor */
+
                        ++buffer;
 
                        /*
index 01dea9b..7588ce1 100644 (file)
@@ -175,7 +175,7 @@ acpi_rs_get_crs_method_data (
  *              and the contents of the callers buffer is undefined.
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_rs_get_prs_method_data (
        acpi_handle                     handle,
@@ -210,6 +210,7 @@ acpi_rs_get_prs_method_data (
        acpi_ut_remove_reference (obj_desc);
        return_ACPI_STATUS (status);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
index d02aa1d..7e736ca 100644 (file)
@@ -41,6 +41,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acresrc.h>
@@ -156,6 +157,7 @@ acpi_get_current_resources (
        status = acpi_rs_get_crs_method_data (device_handle, ret_buffer);
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_get_current_resources);
 
 
 /*******************************************************************************
@@ -178,7 +180,7 @@ acpi_get_current_resources (
  *              and the value of ret_buffer is undefined.
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_get_possible_resources (
        acpi_handle                     device_handle,
@@ -208,6 +210,8 @@ acpi_get_possible_resources (
        status = acpi_rs_get_prs_method_data (device_handle, ret_buffer);
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_get_possible_resources);
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
@@ -310,6 +314,7 @@ cleanup:
        acpi_os_free (buffer.pointer);
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_walk_resources);
 
 
 /*******************************************************************************
@@ -354,6 +359,7 @@ acpi_set_current_resources (
        status = acpi_rs_set_srs_method_data (device_handle, in_buffer);
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_set_current_resources);
 
 
 #define ACPI_COPY_FIELD(out, in, field)  ((out)->field = (in)->field)
@@ -427,3 +433,5 @@ acpi_resource_to_address64 (
 
        return (AE_OK);
 }
+EXPORT_SYMBOL(acpi_resource_to_address64);
+
index bb52f85..d6c0177 100644 (file)
@@ -1,5 +1,5 @@
-obj-y                                  := poweroff.o
-obj-$(CONFIG_ACPI_SLEEP)               += main.o wakeup.o
+obj-y                                  := poweroff.o wakeup.o
+obj-$(CONFIG_ACPI_SLEEP)               += main.o
 obj-$(CONFIG_ACPI_SLEEP_PROC_FS)       += proc.o
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
index 257e16f..da23775 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 #include <acpi/acpi_bus.h>
 #include <linux/sched.h>
+#include "sleep.h"
 
 static void
 acpi_power_off (void)
@@ -16,6 +17,7 @@ acpi_power_off (void)
        printk("%s called\n",__FUNCTION__);
        /* Some SMP machines only can poweroff in boot CPU */
        set_cpus_allowed(current, cpumask_of_cpu(0));
+       acpi_wakeup_gpe_poweroff_prepare();
        acpi_enter_sleep_state_prep(ACPI_STATE_S5);
        ACPI_DISABLE_IRQS();
        acpi_enter_sleep_state(ACPI_STATE_S5);
index 666498e..a94d946 100644 (file)
@@ -70,7 +70,7 @@ acpi_system_write_sleep (
        state = simple_strtoul(str, NULL, 0);
 #ifdef CONFIG_SOFTWARE_SUSPEND
        if (state == 4) {
-               software_suspend();
+               error = software_suspend();
                goto Done;
        }
 #endif
index cfaf8f5..efd0001 100644 (file)
@@ -5,3 +5,4 @@ extern int acpi_suspend (u32 state);
 extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
 extern void acpi_enable_wakeup_device(u8 sleep_state);
 extern void acpi_disable_wakeup_device(u8 sleep_state);
+extern void acpi_wakeup_gpe_poweroff_prepare(void);
index 9c004b9..d9b1999 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * wakeup.c - support wakeup devices
+ * Copyright (C) 2004 Li Shaohua <shaohua.li@intel.com>
  */
 
 #include <linux/init.h>
 #define _COMPONENT             ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME               ("wakeup_devices")
 
+extern struct list_head        acpi_wakeup_device_list;
+extern spinlock_t acpi_device_lock;
+
+#ifdef CONFIG_ACPI_SLEEP
 /**
  * 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(
@@ -179,3 +182,28 @@ static int __init acpi_wakeup_device_init(void)
 }
 
 late_initcall(acpi_wakeup_device_init);
+#endif
+
+/*
+ * Disable all wakeup GPEs before power off.
+ * 
+ * Since acpi_enter_sleep_state() will disable all
+ * RUNTIME GPEs, we simply mark all GPES that
+ * are not enabled for wakeup from S5 as RUNTIME.
+ */
+void acpi_wakeup_gpe_poweroff_prepare(void)
+{
+       struct list_head * node, * next;
+
+       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+               struct acpi_device * dev = container_of(node,
+                       struct acpi_device, wakeup_list);
+
+               /* The GPE can wakeup system from S5, don't touch it */
+               if ((u32)dev->wakeup.sleep_state == ACPI_STATE_S5)
+                       continue;
+               /* acpi_set_gpe_type will automatically disable GPE */
+               acpi_set_gpe_type(dev->wakeup.gpe_device,
+                       dev->wakeup.gpe_number, ACPI_GPE_TYPE_RUNTIME);
+       }
+}
index 1456c7b..5379424 100644 (file)
@@ -167,6 +167,9 @@ acpi_tb_get_table_header (
                return_ACPI_STATUS (AE_BAD_PARAMETER);
        }
 
+       ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n",
+               return_header->signature));
+
        return_ACPI_STATUS (AE_OK);
 }
 
index 79efa36..83d0783 100644 (file)
@@ -266,9 +266,10 @@ acpi_tb_init_table_descriptor (
        if (ACPI_IS_SINGLE_TABLE (acpi_gbl_table_data[table_type].flags)) {
                /*
                 * Only one table allowed, and a table has alread been installed
-                *  at this location, so return an error.
+                * at this location, so return an error.
                 */
                if (list_head->next) {
+                       ACPI_MEM_FREE (table_desc);
                        return_ACPI_STATUS (AE_ALREADY_EXISTS);
                }
 
index fef603f..ac9451d 100644 (file)
@@ -62,7 +62,7 @@
  *              return a pointer to that table descriptor.
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_tb_handle_to_object (
        u16                             table_id,
@@ -90,6 +90,7 @@ acpi_tb_handle_to_object (
        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "table_id=%X does not exist\n", table_id));
        return (AE_BAD_PARAMETER);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
index c92e715..1cce360 100644 (file)
@@ -42,6 +42,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
@@ -137,6 +138,8 @@ error_exit:
 }
 
 
+#ifdef ACPI_FUTURE_USAGE
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_load_table
@@ -343,6 +346,8 @@ acpi_get_table_header (
 }
 
 
+#endif  /*  ACPI_FUTURE_USAGE  */
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_get_table
@@ -439,5 +444,5 @@ acpi_get_table (
        ACPI_MEMCPY ((void *) ret_buffer->pointer, (void *) tbl_ptr, table_length);
        return_ACPI_STATUS (AE_OK);
 }
-
+EXPORT_SYMBOL(acpi_get_table);
 
index 4a96695..b92693c 100644 (file)
@@ -41,6 +41,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/actables.h>
@@ -87,12 +88,28 @@ acpi_tb_find_table (
                return_ACPI_STATUS (AE_AML_STRING_LIMIT);
        }
 
-       /* Find the table */
+       if (!ACPI_STRNCMP (signature, DSDT_SIG, ACPI_NAME_SIZE)) {
+               /*
+                * The DSDT pointer is contained in the FADT, not the RSDT.
+                * This code should suffice, because the only code that would perform
+                * a "find" on the DSDT is the data_table_region() AML opcode -- in
+                * which case, the DSDT is guaranteed to be already loaded.
+                * If this becomes insufficient, the FADT will have to be found first.
+                */
+               if (!acpi_gbl_DSDT) {
+                       return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+               }
 
-       status = acpi_get_firmware_table (signature, 1,
-                          ACPI_LOGICAL_ADDRESSING, &table);
-       if (ACPI_FAILURE (status)) {
-               return_ACPI_STATUS (status);
+               table = acpi_gbl_DSDT;
+       }
+       else {
+               /* Find the table */
+
+               status = acpi_get_firmware_table (signature, 1,
+                                  ACPI_LOGICAL_ADDRESSING, &table);
+               if (ACPI_FAILURE (status)) {
+                       return_ACPI_STATUS (status);
+               }
        }
 
        /* Check oem_id and oem_table_id */
@@ -102,6 +119,7 @@ acpi_tb_find_table (
                return_ACPI_STATUS (AE_AML_NAME_NOT_FOUND);
        }
 
+       ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n", table->signature));
        *table_ptr = table;
        return_ACPI_STATUS (AE_OK);
 }
@@ -304,6 +322,7 @@ cleanup:
        }
        return_ACPI_STATUS (status);
 }
+EXPORT_SYMBOL(acpi_get_firmware_table);
 
 
 /* TBD: Move to a new file */
index 58ec673..1fe8847 100644 (file)
@@ -265,7 +265,7 @@ acpi_ut_validate_buffer (
  * RETURN:      Status
  *
  * DESCRIPTION: Validate that the buffer is of the required length or
- *              allocate a new buffer.
+ *              allocate a new buffer.  Returned buffer is always zeroed.
  *
  ******************************************************************************/
 
@@ -305,24 +305,25 @@ acpi_ut_initialize_buffer (
 
                /* Allocate a new buffer with local interface to allow tracking */
 
-               buffer->pointer = ACPI_MEM_ALLOCATE (required_length);
+               buffer->pointer = ACPI_MEM_CALLOCATE (required_length);
                if (!buffer->pointer) {
                        return (AE_NO_MEMORY);
                }
-
-               /* Clear the buffer */
-
-               ACPI_MEMSET (buffer->pointer, 0, required_length);
                break;
 
 
        default:
 
-               /* Validate the size of the buffer */
+               /* Existing buffer: Validate the size of the buffer */
 
                if (buffer->length < required_length) {
                        status = AE_BUFFER_OVERFLOW;
+                       break;
                }
+
+               /* Clear the buffer */
+
+               ACPI_MEMSET (buffer->pointer, 0, required_length);
                break;
        }
 
@@ -472,7 +473,7 @@ acpi_ut_allocate_and_track (
        acpi_status                     status;
 
 
-       allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_block), component,
+       allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_header), component,
                          module, line);
        if (!allocation) {
                return (NULL);
@@ -518,7 +519,7 @@ acpi_ut_callocate_and_track (
        acpi_status                     status;
 
 
-       allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_block), component,
+       allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_header), component,
                          module, line);
        if (!allocation) {
                /* Report allocation error */
@@ -712,6 +713,7 @@ acpi_ut_track_allocation (
        allocation->line      = line;
 
        ACPI_STRNCPY (allocation->module, module, ACPI_MAX_MODULE_NAME);
+       allocation->module[ACPI_MAX_MODULE_NAME-1] = 0;
 
        /* Insert at list head */
 
@@ -816,7 +818,7 @@ acpi_ut_remove_allocation (
  * DESCRIPTION: Print some info about the outstanding allocations.
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 void
 acpi_ut_dump_allocation_info (
        void)
@@ -862,6 +864,7 @@ acpi_ut_dump_allocation_info (
 */
        return_VOID;
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
index f04e81a..9290313 100644 (file)
@@ -424,23 +424,21 @@ acpi_ut_copy_esimple_to_isimple (
                break;
 
        default:
-               /*
-                * Whatever other type -- it is not supported
-                */
+               /* All other types are not supported */
+
                return_ACPI_STATUS (AE_SUPPORT);
        }
 
 
-       switch (external_object->type) {
-
        /* Must COPY string and buffer contents */
 
+       switch (external_object->type) {
        case ACPI_TYPE_STRING:
 
                internal_object->string.pointer =
                        ACPI_MEM_CALLOCATE ((acpi_size) external_object->string.length + 1);
                if (!internal_object->string.pointer) {
-                       return_ACPI_STATUS (AE_NO_MEMORY);
+                       goto error_exit;
                }
 
                ACPI_MEMCPY (internal_object->string.pointer,
@@ -456,7 +454,7 @@ acpi_ut_copy_esimple_to_isimple (
                internal_object->buffer.pointer =
                        ACPI_MEM_CALLOCATE (external_object->buffer.length);
                if (!internal_object->buffer.pointer) {
-                       return_ACPI_STATUS (AE_NO_MEMORY);
+                       goto error_exit;
                }
 
                ACPI_MEMCPY (internal_object->buffer.pointer,
@@ -479,6 +477,11 @@ acpi_ut_copy_esimple_to_isimple (
 
        *ret_internal_object = internal_object;
        return_ACPI_STATUS (AE_OK);
+
+
+error_exit:
+       acpi_ut_remove_reference (internal_object);
+       return_ACPI_STATUS (AE_NO_MEMORY);
 }
 
 
@@ -747,7 +750,7 @@ acpi_ut_copy_ielement_to_ielement (
 
                        status = acpi_ut_copy_simple_object (source_object, target_object);
                        if (ACPI_FAILURE (status)) {
-                               return (status);
+                               goto error_exit;
                        }
 
                        *this_target_ptr = target_object;
@@ -781,8 +784,8 @@ acpi_ut_copy_ielement_to_ielement (
                        ACPI_MEM_CALLOCATE (((acpi_size) source_object->package.count + 1) *
                                         sizeof (void *));
                if (!target_object->package.elements) {
-                       ACPI_MEM_FREE (target_object);
-                       return (AE_NO_MEMORY);
+                       status = AE_NO_MEMORY;
+                       goto error_exit;
                }
 
                /*
@@ -802,6 +805,10 @@ acpi_ut_copy_ielement_to_ielement (
        }
 
        return (status);
+
+error_exit:
+       acpi_ut_remove_reference (target_object);
+       return (status);
 }
 
 
index 4fc32d5..bf7c41a 100644 (file)
@@ -41,6 +41,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 
@@ -178,6 +179,7 @@ acpi_ut_debug_print (
        va_start (args, format);
        acpi_os_vprintf (format, args);
 }
+EXPORT_SYMBOL(acpi_ut_debug_print);
 
 
 /*****************************************************************************
@@ -219,6 +221,7 @@ acpi_ut_debug_print_raw (
        va_start (args, format);
        acpi_os_vprintf (format, args);
 }
+EXPORT_SYMBOL(acpi_ut_debug_print_raw);
 
 
 /*****************************************************************************
@@ -250,6 +253,7 @@ acpi_ut_trace (
        acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
                        "%s\n", acpi_gbl_fn_entry_str);
 }
+EXPORT_SYMBOL(acpi_ut_trace);
 
 
 /*****************************************************************************
@@ -378,6 +382,7 @@ acpi_ut_exit (
 
        acpi_gbl_nesting_level--;
 }
+EXPORT_SYMBOL(acpi_ut_exit);
 
 
 /*****************************************************************************
@@ -418,6 +423,7 @@ acpi_ut_status_exit (
 
        acpi_gbl_nesting_level--;
 }
+EXPORT_SYMBOL(acpi_ut_status_exit);
 
 
 /*****************************************************************************
@@ -451,6 +457,7 @@ acpi_ut_value_exit (
 
        acpi_gbl_nesting_level--;
 }
+EXPORT_SYMBOL(acpi_ut_value_exit);
 
 
 /*****************************************************************************
index dd57a16..bb5a0f8 100644 (file)
@@ -621,6 +621,10 @@ acpi_ut_add_reference (
                return_VOID;
        }
 
+       ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+               "Obj %p Current Refs=%X [To Be Incremented]\n",
+               object, object->common.reference_count));
+
        /* Increment the reference count */
 
        (void) acpi_ut_update_object_reference (object, REF_INCREMENT);
@@ -664,8 +668,9 @@ acpi_ut_remove_reference (
                return_VOID;
        }
 
-       ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X\n",
-                       object, object->common.reference_count));
+       ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+               "Obj %p Current Refs=%X [To Be Decremented]\n",
+               object, object->common.reference_count));
 
        /*
         * Decrement the reference count, and only actually delete the object
index 573176c..8a2df70 100644 (file)
@@ -59,7 +59,7 @@
  *
  * FUNCTION:    acpi_ut_short_divide
  *
- * PARAMETERS:  in_dividend         - Pointer to the dividend
+ * PARAMETERS:  Dividend            - 64-bit dividend
  *              Divisor             - 32-bit divisor
  *              out_quotient        - Pointer to where the quotient is returned
  *              out_remainder       - Pointer to where the remainder is returned
 
 acpi_status
 acpi_ut_short_divide (
-       acpi_integer                    *in_dividend,
+       acpi_integer                    dividend,
        u32                             divisor,
        acpi_integer                    *out_quotient,
        u32                             *out_remainder)
 {
-       union uint64_overlay            dividend;
+       union uint64_overlay            dividend_ovl;
        union uint64_overlay            quotient;
        u32                             remainder32;
 
 
        ACPI_FUNCTION_TRACE ("ut_short_divide");
 
-       dividend.full = *in_dividend;
 
        /* Always check for a zero divisor */
 
@@ -95,13 +94,15 @@ acpi_ut_short_divide (
                return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
        }
 
+       dividend_ovl.full = dividend;
+
        /*
         * The quotient is 64 bits, the remainder is always 32 bits,
         * and is generated by the second divide.
         */
-       ACPI_DIV_64_BY_32 (0, dividend.part.hi, divisor,
+       ACPI_DIV_64_BY_32 (0, dividend_ovl.part.hi, divisor,
                          quotient.part.hi, remainder32);
-       ACPI_DIV_64_BY_32 (remainder32, dividend.part.lo,  divisor,
+       ACPI_DIV_64_BY_32 (remainder32, dividend_ovl.part.lo, divisor,
                          quotient.part.lo, remainder32);
 
        /* Return only what was requested */
@@ -121,8 +122,8 @@ acpi_ut_short_divide (
  *
  * FUNCTION:    acpi_ut_divide
  *
- * PARAMETERS:  in_dividend         - Pointer to the dividend
- *              in_divisor          - Pointer to the divisor
+ * PARAMETERS:  in_dividend         - Dividend
+ *              in_divisor          - Divisor
  *              out_quotient        - Pointer to where the quotient is returned
  *              out_remainder       - Pointer to where the remainder is returned
  *
@@ -134,8 +135,8 @@ acpi_ut_short_divide (
 
 acpi_status
 acpi_ut_divide (
-       acpi_integer                    *in_dividend,
-       acpi_integer                    *in_divisor,
+       acpi_integer                    in_dividend,
+       acpi_integer                    in_divisor,
        acpi_integer                    *out_quotient,
        acpi_integer                    *out_remainder)
 {
@@ -155,13 +156,13 @@ acpi_ut_divide (
 
        /* Always check for a zero divisor */
 
-       if (*in_divisor == 0) {
+       if (in_divisor == 0) {
                ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
                return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
        }
 
-       divisor.full  = *in_divisor;
-       dividend.full = *in_dividend;
+       divisor.full  = in_divisor;
+       dividend.full = in_dividend;
        if (divisor.part.hi == 0) {
                /*
                 * 1) Simplest case is where the divisor is 32 bits, we can
@@ -269,7 +270,7 @@ acpi_ut_divide (
 
 acpi_status
 acpi_ut_short_divide (
-       acpi_integer                    *in_dividend,
+       acpi_integer                    in_dividend,
        u32                             divisor,
        acpi_integer                    *out_quotient,
        u32                             *out_remainder)
@@ -288,10 +289,10 @@ acpi_ut_short_divide (
        /* Return only what was requested */
 
        if (out_quotient) {
-               *out_quotient = *in_dividend / divisor;
+               *out_quotient = in_dividend / divisor;
        }
        if (out_remainder) {
-               *out_remainder = (u32) *in_dividend % divisor;
+               *out_remainder = (u32) in_dividend % divisor;
        }
 
        return_ACPI_STATUS (AE_OK);
@@ -299,8 +300,8 @@ acpi_ut_short_divide (
 
 acpi_status
 acpi_ut_divide (
-       acpi_integer                    *in_dividend,
-       acpi_integer                    *in_divisor,
+       acpi_integer                    in_dividend,
+       acpi_integer                    in_divisor,
        acpi_integer                    *out_quotient,
        acpi_integer                    *out_remainder)
 {
@@ -309,7 +310,7 @@ acpi_ut_divide (
 
        /* Always check for a zero divisor */
 
-       if (*in_divisor == 0) {
+       if (in_divisor == 0) {
                ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
                return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
        }
@@ -318,10 +319,10 @@ acpi_ut_divide (
        /* Return only what was requested */
 
        if (out_quotient) {
-               *out_quotient = *in_dividend / *in_divisor;
+               *out_quotient = in_dividend / in_divisor;
        }
        if (out_remainder) {
-               *out_remainder = *in_dividend % *in_divisor;
+               *out_remainder = in_dividend % in_divisor;
        }
 
        return_ACPI_STATUS (AE_OK);
index 9efcb99..9cfe115 100644 (file)
@@ -356,16 +356,15 @@ acpi_ut_valid_acpi_character (
  * FUNCTION:    acpi_ut_strtoul64
  *
  * PARAMETERS:  String          - Null terminated string
- *              Terminater      - Where a pointer to the terminating byte is returned
- *              Base            - Radix of the string
+ *              Base            - Radix of the string: 10, 16, or ACPI_ANY_BASE
+ *              ret_integer     - Where the converted integer is returned
  *
- * RETURN:      Converted value
+ * RETURN:      Status and Converted value
  *
  * DESCRIPTION: Convert a string into an unsigned value.
+ *              NOTE: Does not support Octal strings, not needed.
  *
  ******************************************************************************/
-#define NEGATIVE    1
-#define POSITIVE    0
 
 acpi_status
 acpi_ut_strtoul64 (
@@ -373,50 +372,40 @@ acpi_ut_strtoul64 (
        u32                             base,
        acpi_integer                    *ret_integer)
 {
-       u32                             index;
+       u32                             this_digit;
        acpi_integer                    return_value = 0;
-       acpi_status                     status = AE_OK;
-       acpi_integer                    dividend;
        acpi_integer                    quotient;
 
 
-       *ret_integer = 0;
+       ACPI_FUNCTION_TRACE ("ut_stroul64");
+
 
        switch (base) {
-       case 0:
-       case 8:
+       case ACPI_ANY_BASE:
        case 10:
        case 16:
                break;
 
        default:
-               /*
-                * The specified Base parameter is not in the domain of
-                * this function:
-                */
-               return (AE_BAD_PARAMETER);
+               /* Invalid Base */
+               return_ACPI_STATUS (AE_BAD_PARAMETER);
        }
 
-       /*
-        * skip over any white space in the buffer:
-        */
+       /* Skip over any white space in the buffer */
+
        while (ACPI_IS_SPACE (*string) || *string == '\t') {
                ++string;
        }
 
        /*
         * If the input parameter Base is zero, then we need to
-        * determine if it is octal, decimal, or hexadecimal:
+        * determine if it is decimal or hexadecimal:
         */
        if (base == 0) {
-               if (*string == '0') {
-                       if (ACPI_TOLOWER (*(++string)) == 'x') {
-                               base = 16;
-                               ++string;
-                       }
-                       else {
-                               base = 8;
-                       }
+               if ((*string == '0') &&
+                       (ACPI_TOLOWER (*(++string)) == 'x')) {
+                       base = 16;
+                       ++string;
                }
                else {
                        base = 10;
@@ -424,76 +413,67 @@ acpi_ut_strtoul64 (
        }
 
        /*
-        * For octal and hexadecimal bases, skip over the leading
+        * For hexadecimal base, skip over the leading
         * 0 or 0x, if they are present.
         */
-       if (base == 8 && *string == '0') {
-               string++;
-       }
-
        if (base == 16 &&
                *string == '0' &&
                ACPI_TOLOWER (*(++string)) == 'x') {
                string++;
        }
 
-       /* Main loop: convert the string to an unsigned long */
+       /* Main loop: convert the string to a 64-bit integer */
 
        while (*string) {
                if (ACPI_IS_DIGIT (*string)) {
-                       index = ((u8) *string) - '0';
+                       /* Convert ASCII 0-9 to Decimal value */
+
+                       this_digit = ((u8) *string) - '0';
                }
                else {
-                       index = (u8) ACPI_TOUPPER (*string);
-                       if (ACPI_IS_UPPER ((char) index)) {
-                               index = index - 'A' + 10;
+                       this_digit = (u8) ACPI_TOUPPER (*string);
+                       if (ACPI_IS_UPPER ((char) this_digit)) {
+                               /* Convert ASCII Hex char to value */
+
+                               this_digit = this_digit - 'A' + 10;
                        }
                        else {
                                goto error_exit;
                        }
                }
 
-               if (index >= base) {
+               /* Check to see if digit is out of range */
+
+               if (this_digit >= base) {
                        goto error_exit;
                }
 
-               /* Check to see if value is out of range: */
+               /* Divide the digit into the correct position */
 
-               dividend = ACPI_INTEGER_MAX - (acpi_integer) index;
-               (void) acpi_ut_short_divide (&dividend, base, &quotient, NULL);
+               (void) acpi_ut_short_divide ((ACPI_INTEGER_MAX - (acpi_integer) this_digit),
+                                base, &quotient, NULL);
                if (return_value > quotient) {
                        goto error_exit;
                }
 
                return_value *= base;
-               return_value += index;
+               return_value += this_digit;
                ++string;
        }
 
        *ret_integer = return_value;
-       return (status);
+       return_ACPI_STATUS (AE_OK);
 
 
 error_exit:
-       switch (base) {
-       case 8:
-               status = AE_BAD_OCTAL_CONSTANT;
-               break;
+       /* Base was set/validated above */
 
-       case 10:
-               status = AE_BAD_DECIMAL_CONSTANT;
-               break;
-
-       case 16:
-               status = AE_BAD_HEX_CONSTANT;
-               break;
-
-       default:
-               /* Base validated above */
-               break;
+       if (base == 10) {
+               return_ACPI_STATUS (AE_BAD_DECIMAL_CONSTANT);
+       }
+       else {
+               return_ACPI_STATUS (AE_BAD_HEX_CONSTANT);
        }
-
-       return (status);
 }
 
 
@@ -508,7 +488,7 @@ error_exit:
  * DESCRIPTION: Convert string to uppercase
  *
  ******************************************************************************/
-
+#ifdef ACPI_FUTURE_USAGE
 char *
 acpi_ut_strupr (
        char                            *src_string)
@@ -528,6 +508,7 @@ acpi_ut_strupr (
 
        return (src_string);
 }
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /*******************************************************************************
index b3b8757..7346798 100644 (file)
@@ -155,9 +155,8 @@ acpi_ut_create_buffer_object (
        ACPI_FUNCTION_TRACE_U32 ("ut_create_buffer_object", buffer_size);
 
 
-       /*
-        * Create a new Buffer object
-        */
+       /* Create a new Buffer object */
+
        buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
        if (!buffer_desc) {
                return_PTR (NULL);
@@ -189,6 +188,61 @@ acpi_ut_create_buffer_object (
 }
 
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_create_string_object
+ *
+ * PARAMETERS:  string_size            - Size of string to be created.  Does not
+ *                                       include NULL terminator, this is added
+ *                                       automatically.
+ *
+ * RETURN:      Pointer to a new String object
+ *
+ * DESCRIPTION: Create a fully initialized string object
+ *
+ ******************************************************************************/
+
+union acpi_operand_object *
+acpi_ut_create_string_object (
+       acpi_size                       string_size)
+{
+       union acpi_operand_object       *string_desc;
+       char                            *string;
+
+
+       ACPI_FUNCTION_TRACE_U32 ("ut_create_string_object", string_size);
+
+
+       /* Create a new String object */
+
+       string_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
+       if (!string_desc) {
+               return_PTR (NULL);
+       }
+
+       /*
+        * Allocate the actual string buffer -- (Size + 1) for NULL terminator.
+        * NOTE: Zero-length strings are NULL terminated
+        */
+       string = ACPI_MEM_CALLOCATE (string_size + 1);
+       if (!string) {
+               ACPI_REPORT_ERROR (("create_string: could not allocate size %X\n",
+                       (u32) string_size));
+               acpi_ut_remove_reference (string_desc);
+               return_PTR (NULL);
+       }
+
+       /* Complete string object initialization */
+
+       string_desc->string.pointer = string;
+       string_desc->string.length = (u32) string_size;
+
+       /* Return the new string descriptor */
+
+       return_PTR (string_desc);
+}
+
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_valid_internal_object
index 45c14f9..fabe751 100644 (file)
@@ -41,6 +41,7 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acevents.h>
@@ -342,6 +343,8 @@ acpi_terminate (void)
 }
 
 
+#ifdef ACPI_FUTURE_USAGE
+
 /*****************************************************************************
  *
  * FUNCTION:    acpi_subsystem_status
@@ -455,6 +458,7 @@ acpi_get_system_info (
 
        return_ACPI_STATUS (AE_OK);
 }
+EXPORT_SYMBOL(acpi_get_system_info);
 
 
 /*****************************************************************************
@@ -489,6 +493,8 @@ acpi_install_initialization_handler (
        return AE_OK;
 }
 
+#endif  /*  ACPI_FUTURE_USAGE  */
+
 
 /*****************************************************************************
  *
index ed66215..6b35617 100644 (file)
@@ -233,6 +233,7 @@ acpi_extract_package (
 
        return_ACPI_STATUS(AE_OK);
 }
+EXPORT_SYMBOL(acpi_extract_package);
 
 
 acpi_status
@@ -268,6 +269,7 @@ acpi_evaluate_integer (
 
        return_ACPI_STATUS(AE_OK);
 }
+EXPORT_SYMBOL(acpi_evaluate_integer);
 
 
 #if 0
@@ -373,7 +375,7 @@ acpi_evaluate_reference (
        }
 
        if (package->package.count > ACPI_MAX_HANDLES) {
-               return AE_NO_MEMORY;
+               return_ACPI_STATUS(AE_NO_MEMORY);
        }
        list->count = package->package.count;
 
@@ -409,5 +411,5 @@ end:
 
        return_ACPI_STATUS(status);
 }
-
+EXPORT_SYMBOL(acpi_evaluate_reference);
 
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);
index 907c593..d1dcd8e 100644 (file)
@@ -68,4 +68,4 @@ $(obj)/fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \
 # deal with the various suffixes of the binary firmware images
 $(obj)/%.bin $(obj)/%.bin1 $(obj)/%.bin2: $(src)/%.data
        objcopy -Iihex $< -Obinary $@.gz
-       gzip -df $@.gz
+       gzip -n -df $@.gz
index 75681ad..3892dcf 100644 (file)
@@ -649,7 +649,7 @@ struct amb_dev {
   
   struct atm_dev * atm_dev;
   struct pci_dev * pci_dev;
-  struct amb_dev * prev;
+  struct timer_list housekeeping;
 };
 
 typedef struct amb_dev amb_dev;
index 0572f72..381e9c1 100644 (file)
@@ -271,6 +271,28 @@ static void atmtcp_c_close(struct atm_vcc *vcc)
                }
        }
        read_unlock(&vcc_sklist_lock);
+       module_put(THIS_MODULE);
+}
+
+
+static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci)
+{
+        struct hlist_head *head;
+        struct atm_vcc *vcc;
+        struct hlist_node *node;
+        struct sock *s;
+
+        head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)];
+
+        sk_for_each(s, node, head) {
+                vcc = atm_sk(s);
+                if (vcc->dev == dev &&
+                    vcc->vci == vci && vcc->vpi == vpi &&
+                    vcc->qos.rxtp.traffic_class != ATM_NONE) {
+                                return vcc;
+                }
+        }
+        return NULL;
 }
 
 
@@ -278,11 +300,9 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
        struct atm_dev *dev;
        struct atmtcp_hdr *hdr;
-       struct sock *s;
-       struct hlist_node *node;
-       struct atm_vcc *out_vcc = NULL;
+       struct atm_vcc *out_vcc;
        struct sk_buff *new_skb;
-       int i, result = 0;
+       int result = 0;
 
        if (!skb->len) return 0;
        dev = vcc->dev_data;
@@ -293,19 +313,7 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
                goto done;
        }
        read_lock(&vcc_sklist_lock);
-       for(i = 0; i < VCC_HTABLE_SIZE; ++i) {
-               struct hlist_head *head = &vcc_hash[i];
-
-               sk_for_each(s, node, head) {
-                       out_vcc = atm_sk(s);
-                       if (out_vcc->dev != dev)
-                               continue;
-                       if (out_vcc->vpi == ntohs(hdr->vpi) &&
-                           out_vcc->vci == ntohs(hdr->vci) &&
-                           out_vcc->qos.rxtp.traffic_class != ATM_NONE)
-                               break;
-               }
-       }
+       out_vcc = find_vcc(dev, ntohs(hdr->vpi), ntohs(hdr->vci));
        read_unlock(&vcc_sklist_lock);
        if (!out_vcc) {
                atomic_inc(&vcc->stats->tx_err);
index 81127d1..78e34ee 100644 (file)
@@ -245,7 +245,7 @@ static void __iomem *eni_alloc_mem(struct eni_dev *eni_dev, unsigned long *size)
        list = eni_dev->free_list;
        len = eni_dev->free_len;
        if (*size < MID_MIN_BUF_SIZE) *size = MID_MIN_BUF_SIZE;
-       if (*size > MID_MAX_BUF_SIZE) return 0;
+       if (*size > MID_MAX_BUF_SIZE) return NULL;
        for (order = 0; (1 << order) < *size; order++);
        DPRINTK("trying: %ld->%d\n",*size,order);
        best_order = 65; /* we don't have more than 2^64 of anything ... */
@@ -260,7 +260,7 @@ static void __iomem *eni_alloc_mem(struct eni_dev *eni_dev, unsigned long *size)
                                best_order = list[i].order;
                                index = i;
                        }
-       if (best_order == 65) return 0;
+       if (best_order == 65) return NULL;
        start = list[index].start-eni_dev->base_diff;
        list[index] = list[--len];
        eni_dev->free_len = len;
@@ -1315,7 +1315,7 @@ static int reserve_or_set_tx(struct atm_vcc *vcc,struct atm_trafprm *txtp,
                size = UBR_BUFFER;
        }
        new_tx = !eni_vcc->tx;
-       mem = 0; /* for gcc */
+       mem = NULL; /* for gcc */
        if (!new_tx) tx = eni_vcc->tx;
        else {
                mem = eni_alloc_mem(eni_dev,&size);
@@ -1349,7 +1349,7 @@ static int reserve_or_set_tx(struct atm_vcc *vcc,struct atm_trafprm *txtp,
                error = -EINVAL;
        if (error) {
                if (new_tx) {
-                       tx->send = 0;
+                       tx->send = NULL;
                        eni_free_mem(eni_dev,mem,size);
                }
                return error;
@@ -1423,7 +1423,7 @@ static void close_tx(struct atm_vcc *vcc)
                    eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index)))
                        schedule();
                eni_free_mem(eni_dev,eni_vcc->tx->send,eni_vcc->tx->words << 2);
-               eni_vcc->tx->send = 0;
+               eni_vcc->tx->send = NULL;
                eni_dev->tx_bw += eni_vcc->tx->reserved;
        }
        eni_vcc->tx = NULL;
@@ -1444,7 +1444,7 @@ static int start_tx(struct atm_dev *dev)
        skb_queue_head_init(&eni_dev->tx_queue);
        eni_out(0,MID_DMA_WR_TX);
        for (i = 0; i < NR_CHAN; i++) {
-               eni_dev->tx[i].send = 0;
+               eni_dev->tx[i].send = NULL;
                eni_dev->tx[i].index = i;
        }
        return 0;
@@ -1702,7 +1702,7 @@ static int __devinit get_esi_fpga(struct atm_dev *dev, void __iomem *base)
 
 static int __devinit eni_do_init(struct atm_dev *dev)
 {
-       struct midway_eprom *eprom;
+       struct midway_eprom __iomem *eprom;
        struct eni_dev *eni_dev;
        struct pci_dev *pci_dev;
        unsigned long real_base;
@@ -1742,8 +1742,7 @@ static int __devinit eni_do_init(struct atm_dev *dev)
        eni_dev->base_diff = real_base - (unsigned long) base;
        /* id may not be present in ASIC Tonga boards - check this @@@ */
        if (!eni_dev->asic) {
-               eprom = (struct midway_eprom *) (base+EPROM_SIZE-sizeof(struct
-                   midway_eprom));
+               eprom = (base+EPROM_SIZE-sizeof(struct midway_eprom));
                if (readl(&eprom->magic) != ENI155_MAGIC) {
                        printk("\n");
                        printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
@@ -2290,9 +2289,7 @@ static int __init eni_init(void)
                    sizeof(skb->cb),sizeof(struct eni_skb_prv));
                return -EIO;
        }
-       if (pci_register_driver(&eni_driver) > 0) return 0;
-       pci_unregister_driver (&eni_driver);
-       return -ENODEV;
+       return pci_register_driver(&eni_driver);
 }
 
 
index ec5ba49..e2cc702 100644 (file)
@@ -457,7 +457,7 @@ struct hrz_dev {
   unsigned long    unassigned_cell_count;
 
   struct pci_dev * pci_dev;
-  struct hrz_dev * prev;
+  struct timer_list housekeeping;
 };
 
 typedef struct hrz_dev hrz_dev;
index 9da0286..dc6ff86 100644 (file)
@@ -996,18 +996,18 @@ typedef struct _SUNI_STATS_
 
 typedef struct iadev_t {  
        /*-----base pointers into (i)chipSAR+ address space */   
-       u32 *phy;                       /* base pointer into phy(SUNI) */  
-       u32 *dma;                       /* base pointer into DMA control   
+       u32 __iomem *phy;               /* base pointer into phy(SUNI) */  
+       u32 __iomem *dma;               /* base pointer into DMA control   
                                                registers */  
-       u32 *reg;                       /* base pointer to SAR registers  
+       u32 __iomem *reg;               /* base pointer to SAR registers  
                                           - Bus Interface Control Regs */  
-       u32 *seg_reg;                   /* base pointer to segmentation engine  
+       u32 __iomem *seg_reg;           /* base pointer to segmentation engine  
                                                internal registers */  
-       u32 *reass_reg;                 /* base pointer to reassemble engine  
+       u32 __iomem *reass_reg;         /* base pointer to reassemble engine  
                                                internal registers */  
-       u32 *ram;                       /* base pointer to SAR RAM */  
-       unsigned int seg_ram;  
-       unsigned int reass_ram;  
+       u32 __iomem *ram;               /* base pointer to SAR RAM */  
+       void __iomem *seg_ram;  
+       void __iomem *reass_ram;  
        struct dle_q tx_dle_q;  
        struct free_desc_q *tx_free_desc_qhead;  
        struct sk_buff_head tx_dma_q, tx_backlog;  
@@ -1019,7 +1019,7 @@ typedef struct iadev_t {
        struct cpcs_trailer_desc *tx_buf;
         u16 num_tx_desc, tx_buf_sz, rate_limit;
         u32 tx_cell_cnt, tx_pkt_cnt;
-        u32 MAIN_VC_TABLE_ADDR, EXT_VC_TABLE_ADDR, ABR_SCHED_TABLE_ADDR;
+        void __iomem *MAIN_VC_TABLE_ADDR, *EXT_VC_TABLE_ADDR, *ABR_SCHED_TABLE_ADDR;
        struct dle_q rx_dle_q;  
        struct free_desc_q *rx_free_desc_qhead;  
        struct sk_buff_head rx_dma_q;  
@@ -1027,13 +1027,13 @@ typedef struct iadev_t {
        struct atm_vcc **rx_open;       /* list of all open VCs */  
         u16 num_rx_desc, rx_buf_sz, rxing;
         u32 rx_pkt_ram, rx_tmp_cnt, rx_tmp_jif;
-        u32 RX_DESC_BASE_ADDR;
+        void __iomem *RX_DESC_BASE_ADDR;
         u32 drop_rxpkt, drop_rxcell, rx_cell_cnt, rx_pkt_cnt;
        struct atm_dev *next_board;     /* other iphase devices */  
        struct pci_dev *pci;  
        int mem;  
-       unsigned long base_diff;        /* virtual - real base address */  
-       unsigned int real_base, base;   /* real and virtual base address */  
+       unsigned int real_base; /* real and virtual base address */  
+       void __iomem *base;
        unsigned int pci_map_size;      /*pci map size of board */  
        unsigned char irq;  
        unsigned char bus;  
index 3f18782..e6fb0b3 100644 (file)
@@ -267,7 +267,7 @@ static struct atmdev_ops atm_ops =
 };
 static struct timer_list ns_timer;
 static char *mac[NS_MAX_CARDS];
-MODULE_PARM(mac, "1-" __MODULE_STRING(NS_MAX_CARDS) "s");
+module_param_array(mac, charp, NULL, 0);
 MODULE_LICENSE("GPL");
 
 
index 88d548a..6ed9ddb 100644 (file)
@@ -46,6 +46,8 @@
  *  - OAM
  */
 
+#define ZATM_COPPER    1
+
 #if 0
 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
 #else
@@ -1577,51 +1579,77 @@ static const struct atmdev_ops ops = {
        .change_qos     = zatm_change_qos,
 };
 
-static int __init zatm_module_init(void)
+static int __devinit zatm_init_one(struct pci_dev *pci_dev,
+                                  const struct pci_device_id *ent)
 {
        struct atm_dev *dev;
        struct zatm_dev *zatm_dev;
-       int devs,type;
-
-       zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct zatm_dev),
-           GFP_KERNEL);
-       if (!zatm_dev) return -ENOMEM;
-       devs = 0;
-       for (type = 0; type < 2; type++) {
-               struct pci_dev *pci_dev;
-
-               pci_dev = NULL;
-               while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ?
-                   PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221,
-                   pci_dev))) {
-                       if (pci_enable_device(pci_dev)) break;
-                       dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
-                       if (!dev) break;
-                       zatm_dev->pci_dev = pci_dev;
-                       dev->dev_data = zatm_dev;
-                       zatm_dev->copper = type;
-                       if (zatm_init(dev) || zatm_start(dev)) {
-                               atm_dev_deregister(dev);
-                               break;
-                       }
-                       zatm_dev->more = zatm_boards;
-                       zatm_boards = dev;
-                       devs++;
-                       zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct
-                           zatm_dev),GFP_KERNEL);
-                       if (!zatm_dev) {
-                               printk(KERN_EMERG "zatm.c: memory shortage\n");
-                               goto out;
-                       }
-               }
+       int ret = -ENOMEM;
+
+       zatm_dev = (struct zatm_dev *) kmalloc(sizeof(*zatm_dev), GFP_KERNEL);
+       if (!zatm_dev) {
+               printk(KERN_EMERG "%s: memory shortage\n", DEV_LABEL);
+               goto out;
        }
+
+       dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+       if (!dev)
+               goto out_free;
+
+       ret = pci_enable_device(pci_dev);
+       if (ret < 0)
+               goto out_deregister;
+
+       ret = pci_request_regions(pci_dev, DEV_LABEL);
+       if (ret < 0)
+               goto out_disable;
+
+       zatm_dev->pci_dev = pci_dev;
+       dev = (struct atm_dev *)zatm_dev;
+       zatm_dev->copper = (int)ent->driver_data;
+       if ((ret = zatm_init(dev)) || (ret = zatm_start(dev)))
+               goto out_release;
+
+       pci_set_drvdata(pci_dev, dev);
+       zatm_dev->more = zatm_boards;
+       zatm_boards = dev;
+       ret = 0;
 out:
+       return ret;
+
+out_release:
+       pci_release_regions(pci_dev);
+out_disable:
+       pci_disable_device(pci_dev);
+out_deregister:
+       atm_dev_deregister(dev);
+out_free:
        kfree(zatm_dev);
-
-       return 0;
+       goto out;
 }
 
+
 MODULE_LICENSE("GPL");
 
-module_init(zatm_module_init);
+static struct pci_device_id zatm_pci_tbl[] __devinitdata = {
+       { PCI_VENDOR_ID_ZEITNET, PCI_DEVICE_ID_ZEITNET_1221,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, ZATM_COPPER },
+       { PCI_VENDOR_ID_ZEITNET, PCI_DEVICE_ID_ZEITNET_1225,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, zatm_pci_tbl);
+
+static struct pci_driver zatm_driver = {
+       .name =         DEV_LABEL,
+       .id_table =     zatm_pci_tbl,
+       .probe =        zatm_init_one,
+};
+
+static int __init zatm_init_module(void)
+{
+       return pci_module_init(&zatm_driver);
+}
+
+module_init(zatm_init_module);
 /* module_exit not defined so not unloadable */
index d938c5f..6070a48 100644 (file)
@@ -1,5 +1,8 @@
+
+menu "IO Schedulers"
+
 config IOSCHED_NOOP
-       bool "No-op I/O scheduler" if EMBEDDED
+       bool
        default y
        ---help---
          The no-op I/O scheduler is a minimal scheduler that does basic merging
@@ -9,7 +12,7 @@ config IOSCHED_NOOP
          the kernel.
 
 config IOSCHED_AS
-       bool "Anticipatory I/O scheduler" if EMBEDDED
+       tristate "Anticipatory I/O scheduler"
        default y
        ---help---
          The anticipatory I/O scheduler is the default disk scheduler. It is
@@ -18,7 +21,7 @@ config IOSCHED_AS
          slower in some cases especially some database loads.
 
 config IOSCHED_DEADLINE
-       bool "Deadline I/O scheduler" if EMBEDDED
+       tristate "Deadline I/O scheduler"
        default y
        ---help---
          The deadline I/O scheduler is simple and compact, and is often as
@@ -28,9 +31,11 @@ config IOSCHED_DEADLINE
          anticipatory I/O scheduler and so is a good choice.
 
 config IOSCHED_CFQ
-       bool "CFQ I/O scheduler" if EMBEDDED
+       tristate "CFQ I/O scheduler"
        default y
        ---help---
          The CFQ I/O scheduler tries to distribute bandwidth equally
          among all processes in the system. It should provide a fair
          working environment, suitable for desktop systems.
+
+endmenu
index 62e3a7e..19ca2e5 100644 (file)
 #define FD_HD_3        0x55555555  /* high-density 3.5" (1760K) drive */
 #define FD_DD_5        0xaaaaaaaa  /* double-density 5.25" (440K) drive */
 
-static long int fd_def_df0 = FD_DD_3;     /* default for df0 if it doesn't identify */
+static unsigned long int fd_def_df0 = FD_DD_3;     /* default for df0 if it doesn't identify */
 
-MODULE_PARM(fd_def_df0,"l");
+module_param(fd_def_df0, ulong, 0);
 MODULE_LICENSE("GPL");
 
 static struct request_queue *floppy_queue;
index ffef40b..707dddd 100644 (file)
@@ -83,12 +83,31 @@ struct request *elevator_noop_next_request(request_queue_t *q)
        return NULL;
 }
 
-elevator_t elevator_noop = {
-       .elevator_merge_fn              = elevator_noop_merge,
-       .elevator_merge_req_fn          = elevator_noop_merge_requests,
-       .elevator_next_req_fn           = elevator_noop_next_request,
-       .elevator_add_req_fn            = elevator_noop_add_request,
-       .elevator_name                  = "noop",
+static struct elevator_type elevator_noop = {
+       .ops = {
+               .elevator_merge_fn              = elevator_noop_merge,
+               .elevator_merge_req_fn          = elevator_noop_merge_requests,
+               .elevator_next_req_fn           = elevator_noop_next_request,
+               .elevator_add_req_fn            = elevator_noop_add_request,
+       },
+       .elevator_name = "noop",
+       .elevator_owner = THIS_MODULE,
 };
 
-EXPORT_SYMBOL(elevator_noop);
+int noop_init(void)
+{
+       return elv_register(&elevator_noop);
+}
+
+void noop_exit(void)
+{
+       elv_unregister(&elevator_noop);
+}
+
+module_init(noop_init);
+module_exit(noop_exit);
+
+
+MODULE_AUTHOR("Jens Axboe");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("No-op IO scheduler");
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);
index f605535..1e6784b 100644 (file)
@@ -8,13 +8,11 @@
  * 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?)
+ *  -- Do resets with usb_device_reset (needs a thread context, use khubd)
  *  -- 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
@@ -25,6 +23,7 @@
  *  -- prune comments, they are too volumnous
  *  -- Exterminate P3 printks
  *  -- Resove XXX's
+ *  -- Redo "benh's retries", perhaps have spin-up code to handle them. V:D=?
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -37,7 +36,7 @@
 #define DRV_NAME "ub"
 #define DEVFS_NAME DRV_NAME
 
-#define UB_MAJOR 125   /* Stolen from Experimental range for a week - XXX */
+#define UB_MAJOR 180
 
 /*
  * Definitions which have to be scattered once we understand the layout better.
@@ -62,9 +61,9 @@
 
 /* command block wrapper */
 struct bulk_cb_wrap {
-       u32     Signature;              /* contains 'USBC' */
+       __le32  Signature;              /* contains 'USBC' */
        u32     Tag;                    /* unique per command id */
-       u32     DataTransferLength;     /* size of data */
+       __le32  DataTransferLength;     /* size of data */
        u8      Flags;                  /* direction in bit 0 */
        u8      Lun;                    /* LUN normally 0 */
        u8      Length;                 /* of of the CDB */
@@ -78,9 +77,9 @@ struct bulk_cb_wrap {
 
 /* command status wrapper */
 struct bulk_cs_wrap {
-       u32     Signature;              /* should = 'USBS' */
+       __le32  Signature;              /* should = 'USBS' */
        u32     Tag;                    /* same as original command */
-       u32     Residue;                /* amount not transferred */
+       __le32  Residue;                /* amount not transferred */
        u8      Status;                 /* see below */
 };
 
@@ -104,13 +103,11 @@ struct ub_dev;
 #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.
+ * A second is more than enough for a 32K transfer (UB_MAX_SECTORS)
+ * even if a webcam hogs the bus, but some devices need time to spin up.
  */
 #define UB_URB_TIMEOUT (HZ*2)
+#define UB_DATA_TIMEOUT        (HZ*5)  /* ZIP does spin-ups in the data phase */
 #define UB_CTRL_TIMEOUT        (HZ/2) /* 500ms ought to be enough to clear a stall */
 
 /*
@@ -157,7 +154,8 @@ struct ub_scsi_cmd {
        struct ub_scsi_cmd *next;
 
        int error;                      /* Return code - valid upon done */
-       int act_len;                    /* Return size */
+       unsigned int act_len;           /* Return size */
+       unsigned char key, asc, ascq;   /* May be valid if error==-EIO */
 
        int stat_count;                 /* Retries getting status. */
 
@@ -186,7 +184,7 @@ struct ub_capacity {
  */
 
 #define SCMD_ST_HIST_SZ   8
-#define SCMD_TRACE_SZ    15    /* No more than 256 (trace_index) */
+#define SCMD_TRACE_SZ    63            /* Less than 4KB of 61-byte lines */
 
 struct ub_scsi_cmd_trace {
        int hcur;
@@ -265,6 +263,7 @@ struct ub_dev {
        int changed;                    /* Media was changed */
        int removable;
        int readonly;
+       int first_open;                 /* Kludge. See ub_bd_open. */
        char name[8];
        struct usb_device *dev;
        struct usb_interface *intf;
@@ -490,6 +489,18 @@ static void ub_id_put(int id)
  */
 static void ub_cleanup(struct ub_dev *sc)
 {
+
+       /*
+        * 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(sc->disk);
+       sc->disk = NULL;
+
        ub_id_put(sc->id);
        kfree(sc);
 }
@@ -661,9 +672,12 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q)
 
        /*
         * build the command
+        *
+        * The call to blk_queue_hardsect_size() guarantees that request
+        * is aligned, but it is given in terms of 512 byte units, always.
         */
-       block = rq->sector;
-       nblks = rq->nr_sectors;
+       block = rq->sector >> sc->capacity.bshift;
+       nblks = rq->nr_sectors >> sc->capacity.bshift;
 
        memset(cmd, 0, sizeof(struct ub_scsi_cmd));
        cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10;
@@ -678,7 +692,7 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q)
        cmd->dir = ub_dir;
        cmd->state = UB_CMDST_INIT;
        cmd->data = rq->buffer;
-       cmd->len = nblks * 512;
+       cmd->len = rq->nr_sectors * 512;
        cmd->done = ub_rw_cmd_done;
        cmd->back = rq;
 
@@ -786,17 +800,16 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        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;
        }
 
+       sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+       add_timer(&sc->work_timer);
+
        cmd->state = UB_CMDST_CMD;
        ub_cmdtr_state(sc, cmd);
        return 0;
@@ -836,6 +849,7 @@ static void ub_scsi_action(unsigned long _dev)
        unsigned long flags;
 
        spin_lock_irqsave(&sc->lock, flags);
+       del_timer(&sc->work_timer);
        ub_scsi_dispatch(sc);
        spin_unlock_irqrestore(&sc->lock, flags);
 }
@@ -871,9 +885,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        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;
@@ -942,9 +953,12 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        ub_cmdtr_state(sc, cmd);
                        return;
                }
-               if (urb->status != 0)
+               if (urb->status != 0) {
+                       printk("ub: cmd #%d cmd status (%d)\n", cmd->tag, urb->status); /* P3 */
                        goto Bad_End;
+               }
                if (urb->actual_length != US_BULK_CB_WRAP_LEN) {
+                       printk("ub: cmd #%d xferred %d\n", cmd->tag, urb->actual_length); /* P3 */
                        /* XXX Must do reset here to unconfuse the device */
                        goto Bad_End;
                }
@@ -968,18 +982,17 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                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;
                }
 
+               sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
+               add_timer(&sc->work_timer);
+
                cmd->state = UB_CMDST_DATA;
                ub_cmdtr_state(sc, cmd);
 
@@ -1063,19 +1076,18 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        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;
                        }
+
+                       sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+                       add_timer(&sc->work_timer);
                        return;
                }
 
@@ -1132,16 +1144,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                (*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",
@@ -1186,18 +1190,17 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        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;
        }
 
+       sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+       add_timer(&sc->work_timer);
+
        cmd->stat_count = 0;
        cmd->state = UB_CMDST_STAT;
        ub_cmdtr_state(sc, cmd);
@@ -1217,9 +1220,17 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                goto error;
        }
 
+       /*
+        * ``If the allocation length is eighteen or greater, and a device
+        * server returns less than eithteen bytes of data, the application
+        * client should assume that the bytes not transferred would have been
+        * zeroes had the device server returned those bytes.''
+        */
        memset(&sc->top_sense, 0, UB_SENSE_SIZE);
+
        scmd = &sc->top_rqs_cmd;
        scmd->cdb[0] = REQUEST_SENSE;
+       scmd->cdb[4] = UB_SENSE_SIZE;
        scmd->cdb_len = 6;
        scmd->dir = UB_DIR_READ;
        scmd->state = UB_CMDST_INIT;
@@ -1271,14 +1282,13 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
        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;
        }
+
+       sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT;
+       add_timer(&sc->work_timer);
        return 0;
 }
 
@@ -1289,8 +1299,15 @@ 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;
 
+       /*
+        * Ignoring scmd->act_len, because the buffer was pre-zeroed.
+        */
        ub_cmdtr_sense(sc, scmd, sense);
 
+       /*
+        * Find the command which triggered the unit attention or a check,
+        * save the sense into it, and advance its state machine.
+        */
        if ((cmd = ub_cmdq_peek(sc)) == NULL) {
                printk(KERN_WARNING "%s: sense done while idle\n", sc->name);
                return;
@@ -1308,6 +1325,10 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
                return;
        }
 
+       cmd->key = sense[2] & 0x0F;
+       cmd->asc = sense[12];
+       cmd->ascq = sense[13];
+
        ub_scsi_urb_compl(sc, cmd);
 }
 
@@ -1355,12 +1376,7 @@ 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.nsec = 0;
        sc->capacity.bsize = 512;
        sc->capacity.bshift = 0;
 
@@ -1375,7 +1391,7 @@ static void ub_revalidate(struct ub_dev *sc)
                 * 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.nsec = 0;
                        sc->capacity.bsize = 512;
                        sc->capacity.bshift = 0;
                }
@@ -1404,10 +1420,38 @@ static int ub_bd_open(struct inode *inode, struct file *filp)
        sc->openc++;
        spin_unlock_irqrestore(&ub_lock, flags);
 
+       /*
+        * This is a workaround for a specific problem in our block layer.
+        * In 2.6.9, register_disk duplicates the code from rescan_partitions.
+        * However, if we do add_disk with a device which persistently reports
+        * a changed media, add_disk calls register_disk, which does do_open,
+        * which will call rescan_paritions for changed media. After that,
+        * register_disk attempts to do it all again and causes double kobject
+        * registration and a eventually an oops on module removal.
+        *
+        * The bottom line is, Al Viro says that we should not allow
+        * bdev->bd_invalidated to be set when doing add_disk no matter what.
+        */
+       if (sc->first_open) {
+               if (sc->changed) {
+                       sc->first_open = 0;
+                       rc = -ENOMEDIUM;
+                       goto err_open;
+               }
+       }
+
        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. */
+       /*
+        * The sd.c considers ->media_present and ->changed not equivalent,
+        * under some pretty murky conditions (a failure of READ CAPACITY).
+        * We may need it one day.
+        */
+       if (sc->removable && sc->changed && !(filp->f_flags & O_NDELAY)) {
+               rc = -ENOMEDIUM;
+               goto err_open;
+       }
 
        if (sc->readonly && (filp->f_mode & FMODE_WRITE)) {
                rc = -EROFS;
@@ -1435,6 +1479,8 @@ static int ub_bd_release(struct inode *inode, struct file *filp)
 
        spin_lock_irqsave(&ub_lock, flags);
        --sc->openc;
+       if (sc->openc == 0)
+               sc->first_open = 0;
        if (sc->openc == 0 && atomic_read(&sc->poison))
                ub_cleanup(sc);
        spin_unlock_irqrestore(&ub_lock, flags);
@@ -1489,11 +1535,17 @@ static int ub_bd_revalidate(struct gendisk *disk)
 
        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);
+       if (!atomic_read(&sc->poison)) {                /* Cover sc->dev */
+               printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n",
+                   sc->name, sc->dev->devnum,
+                   sc->capacity.nsec, sc->capacity.bsize);
+       }
 
+       /* XXX Support sector size switching like in sr.c */
+       blk_queue_hardsect_size(disk->queue, sc->capacity.bsize);
        set_capacity(disk, sc->capacity.nsec);
        // set_disk_ro(sdkp->disk, sc->readonly);
+
        return 0;
 }
 
@@ -1524,13 +1576,9 @@ static int ub_bd_media_changed(struct gendisk *disk)
         */
        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;
 }
 
@@ -1592,6 +1640,9 @@ static int ub_sync_tur(struct ub_dev *sc)
 
        rc = cmd->error;
 
+       if (rc == -EIO && cmd->key != 0)        /* Retries for benh's key */
+               rc = cmd->key;
+
 err_submit:
        kfree(cmd);
 err_alloc:
@@ -1654,8 +1705,8 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret)
        }
 
        /* 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));
+       nsec = be32_to_cpu(*(__be32 *)p) + 1;
+       bsize = be32_to_cpu(*(__be32 *)(p + 4));
        switch (bsize) {
        case 512:       shift = 0;      break;
        case 1024:      shift = 1;      break;
@@ -1725,28 +1776,22 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
        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;
        }
 
+       init_timer(&timer);
+       timer.function = ub_probe_timeout;
+       timer.data = (unsigned long) &compl;
+       timer.expires = jiffies + UB_CTRL_TIMEOUT;
+       add_timer(&timer);
+
        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);
+       usb_kill_urb(&sc->work_urb);
 
        /* reset the endpoint toggle */
        usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0);
@@ -1813,6 +1858,7 @@ static int ub_probe(struct usb_interface *intf,
        request_queue_t *q;
        struct gendisk *disk;
        int rc;
+       int i;
 
        rc = -ENOMEM;
        if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
@@ -1879,9 +1925,15 @@ static int ub_probe(struct usb_interface *intf,
         * 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);
+       for (i = 0; i < 3; i++) {       /* Retries for benh's key */
+               if ((rc = ub_sync_tur(sc)) <= 0) break;
+               if (rc != 0x6) break;
+               msleep(10);
+       }
 
        sc->removable = 1;              /* XXX Query this from the device */
+       sc->changed = 1;                /* ub_revalidate clears only */
+       sc->first_open = 1;
 
        ub_revalidate(sc);
        /* This is pretty much a long term P3 */
@@ -1915,7 +1967,7 @@ static int ub_probe(struct usb_interface *intf,
        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);
+       blk_queue_hardsect_size(q, sc->capacity.bsize);
 
        /*
         * This is a serious infraction, caused by a deficiency in the
@@ -2005,17 +2057,6 @@ static void ub_disconnect(struct usb_interface *intf)
        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.
@@ -2034,6 +2075,13 @@ static void ub_disconnect(struct usb_interface *intf)
        }
        spin_unlock_irqrestore(&sc->lock, flags);
 
+       /*
+        * There is virtually no chance that other CPU runs times so long
+        * after ub_urb_complete should have called del_timer, but only if HCD
+        * didn't forget to deliver a callback on unlink.
+        */
+       del_timer_sync(&sc->work_timer);
+
        /*
         * At this point there must be no commands coming from anyone
         * and no URBs left in transit.
index 958a5e1..8dc8894 100644 (file)
@@ -32,9 +32,9 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/blkdev.h>
+#include <linux/bitops.h>
 
 #include <asm/setup.h>
-#include <asm/bitops.h>
 #include <asm/amigahw.h>
 #include <asm/pgtable.h>
 
index 54ef5f9..4db1fee 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
+#include <linux/moduleparam.h>
+
 #include <linux/skbuff.h>
 #include <asm/io.h>
 
 
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0x86bc;
+static unsigned int irq_mask = 0x86bc;
 static int irq_list[4] = { -1 };
 
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
+module_param(irq_mask, uint, 0);
+module_param_array(irq_list, int, NULL, 0);
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)");
@@ -90,14 +92,14 @@ typedef struct bluecard_info_t {
 } bluecard_info_t;
 
 
-void bluecard_config(dev_link_t *link);
-void bluecard_release(dev_link_t *link);
-int bluecard_event(event_t event, int priority, event_callback_args_t *args);
+static void bluecard_config(dev_link_t *link);
+static void bluecard_release(dev_link_t *link);
+static int bluecard_event(event_t event, int priority, event_callback_args_t *args);
 
 static dev_info_t dev_info = "bluecard_cs";
 
-dev_link_t *bluecard_attach(void);
-void bluecard_detach(dev_link_t *);
+static dev_link_t *bluecard_attach(void);
+static void bluecard_detach(dev_link_t *);
 
 static dev_link_t *dev_list = NULL;
 
@@ -170,7 +172,7 @@ static dev_link_t *dev_list = NULL;
 /* ======================== LED handling routines ======================== */
 
 
-void bluecard_activity_led_timeout(u_long arg)
+static void bluecard_activity_led_timeout(u_long arg)
 {
        bluecard_info_t *info = (bluecard_info_t *)arg;
        unsigned int iobase = info->link.io.BasePort1;
@@ -719,7 +721,7 @@ static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned l
 /* ======================== Card services HCI interaction ======================== */
 
 
-int bluecard_open(bluecard_info_t *info)
+static int bluecard_open(bluecard_info_t *info)
 {
        unsigned int iobase = info->link.io.BasePort1;
        struct hci_dev *hdev;
@@ -837,7 +839,7 @@ int bluecard_open(bluecard_info_t *info)
 }
 
 
-int bluecard_close(bluecard_info_t *info)
+static int bluecard_close(bluecard_info_t *info)
 {
        unsigned int iobase = info->link.io.BasePort1;
        struct hci_dev *hdev = info->hdev;
@@ -864,7 +866,7 @@ int bluecard_close(bluecard_info_t *info)
        return 0;
 }
 
-dev_link_t *bluecard_attach(void)
+static dev_link_t *bluecard_attach(void)
 {
        bluecard_info_t *info;
        client_reg_t client_reg;
@@ -922,7 +924,7 @@ dev_link_t *bluecard_attach(void)
 }
 
 
-void bluecard_detach(dev_link_t *link)
+static void bluecard_detach(dev_link_t *link)
 {
        bluecard_info_t *info = link->priv;
        dev_link_t **linkp;
@@ -967,7 +969,7 @@ static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse
        return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-void bluecard_config(dev_link_t *link)
+static void bluecard_config(dev_link_t *link)
 {
        client_handle_t handle = link->handle;
        bluecard_info_t *info = link->priv;
@@ -1042,7 +1044,7 @@ failed:
 }
 
 
-void bluecard_release(dev_link_t *link)
+static void bluecard_release(dev_link_t *link)
 {
        bluecard_info_t *info = link->priv;
 
@@ -1061,7 +1063,7 @@ void bluecard_release(dev_link_t *link)
 }
 
 
-int bluecard_event(event_t event, int priority, event_callback_args_t *args)
+static int bluecard_event(event_t event, int priority, event_callback_args_t *args)
 {
        dev_link_t *link = args->client_data;
        bluecard_info_t *info = link->priv;
index b44fa7d..74644df 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
+#include <linux/moduleparam.h>
 
 #include <linux/skbuff.h>
 #include <linux/string.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
+#include <linux/bitops.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 
 #include <pcmcia/version.h>
 
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xffff;
+static unsigned int irq_mask = 0xffff;
 static int irq_list[4] = { -1 };
 
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
+module_param(irq_mask, uint, 0);
+module_param_array(irq_list, int, NULL, 0);
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth driver for Bluetooth PCMCIA cards with HCI UART interface");
@@ -91,14 +92,14 @@ typedef struct btuart_info_t {
 } btuart_info_t;
 
 
-void btuart_config(dev_link_t *link);
-void btuart_release(dev_link_t *link);
-int btuart_event(event_t event, int priority, event_callback_args_t *args);
+static void btuart_config(dev_link_t *link);
+static void btuart_release(dev_link_t *link);
+static int btuart_event(event_t event, int priority, event_callback_args_t *args);
 
 static dev_info_t dev_info = "btuart_cs";
 
-dev_link_t *btuart_attach(void);
-void btuart_detach(dev_link_t *);
+static dev_link_t *btuart_attach(void);
+static void btuart_detach(dev_link_t *);
 
 static dev_link_t *dev_list = NULL;
 
@@ -491,7 +492,7 @@ static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned lon
 /* ======================== Card services HCI interaction ======================== */
 
 
-int btuart_open(btuart_info_t *info)
+static int btuart_open(btuart_info_t *info)
 {
        unsigned long flags;
        unsigned int iobase = info->link.io.BasePort1;
@@ -560,7 +561,7 @@ int btuart_open(btuart_info_t *info)
 }
 
 
-int btuart_close(btuart_info_t *info)
+static int btuart_close(btuart_info_t *info)
 {
        unsigned long flags;
        unsigned int iobase = info->link.io.BasePort1;
@@ -589,7 +590,7 @@ int btuart_close(btuart_info_t *info)
        return 0;
 }
 
-dev_link_t *btuart_attach(void)
+static dev_link_t *btuart_attach(void)
 {
        btuart_info_t *info;
        client_reg_t client_reg;
@@ -647,7 +648,7 @@ dev_link_t *btuart_attach(void)
 }
 
 
-void btuart_detach(dev_link_t *link)
+static void btuart_detach(dev_link_t *link)
 {
        btuart_info_t *info = link->priv;
        dev_link_t **linkp;
@@ -701,7 +702,7 @@ static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
        return get_tuple(handle, tuple, parse);
 }
 
-void btuart_config(dev_link_t *link)
+static void btuart_config(dev_link_t *link)
 {
        static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        client_handle_t handle = link->handle;
@@ -815,7 +816,7 @@ failed:
 }
 
 
-void btuart_release(dev_link_t *link)
+static void btuart_release(dev_link_t *link)
 {
        btuart_info_t *info = link->priv;
 
@@ -832,7 +833,7 @@ void btuart_release(dev_link_t *link)
 }
 
 
-int btuart_event(event_t event, int priority, event_callback_args_t *args)
+static int btuart_event(event_t event, int priority, event_callback_args_t *args)
 {
        dev_link_t *link = args->client_data;
        btuart_info_t *info = link->priv;
index 79ec1ce..87ff796 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
+#include <linux/moduleparam.h>
 
 #include <linux/skbuff.h>
 #include <linux/string.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
+#include <linux/bitops.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 
 #include <pcmcia/version.h>
 
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xffff;
+static unsigned int irq_mask = 0xffff;
 static int irq_list[4] = { -1 };
 
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
+module_param(irq_mask, uint, 0);
+module_param_array(irq_list, int, NULL, 0);
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth driver for Nokia Connectivity Card DTL-1");
@@ -94,14 +95,14 @@ typedef struct dtl1_info_t {
 } dtl1_info_t;
 
 
-void dtl1_config(dev_link_t *link);
-void dtl1_release(dev_link_t *link);
-int dtl1_event(event_t event, int priority, event_callback_args_t *args);
+static void dtl1_config(dev_link_t *link);
+static void dtl1_release(dev_link_t *link);
+static int dtl1_event(event_t event, int priority, event_callback_args_t *args);
 
 static dev_info_t dev_info = "dtl1_cs";
 
-dev_link_t *dtl1_attach(void);
-void dtl1_detach(dev_link_t *);
+static dev_link_t *dtl1_attach(void);
+static void dtl1_detach(dev_link_t *);
 
 static dev_link_t *dev_list = NULL;
 
@@ -468,7 +469,7 @@ static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long
 /* ======================== Card services HCI interaction ======================== */
 
 
-int dtl1_open(dtl1_info_t *info)
+static int dtl1_open(dtl1_info_t *info)
 {
        unsigned long flags;
        unsigned int iobase = info->link.io.BasePort1;
@@ -539,7 +540,7 @@ int dtl1_open(dtl1_info_t *info)
 }
 
 
-int dtl1_close(dtl1_info_t *info)
+static int dtl1_close(dtl1_info_t *info)
 {
        unsigned long flags;
        unsigned int iobase = info->link.io.BasePort1;
@@ -568,7 +569,7 @@ int dtl1_close(dtl1_info_t *info)
        return 0;
 }
 
-dev_link_t *dtl1_attach(void)
+static dev_link_t *dtl1_attach(void)
 {
        dtl1_info_t *info;
        client_reg_t client_reg;
@@ -626,7 +627,7 @@ dev_link_t *dtl1_attach(void)
 }
 
 
-void dtl1_detach(dev_link_t *link)
+static void dtl1_detach(dev_link_t *link)
 {
        dtl1_info_t *info = link->priv;
        dev_link_t **linkp;
@@ -680,7 +681,7 @@ static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
        return get_tuple(handle, tuple, parse);
 }
 
-void dtl1_config(dev_link_t *link)
+static void dtl1_config(dev_link_t *link)
 {
        client_handle_t handle = link->handle;
        dtl1_info_t *info = link->priv;
@@ -767,7 +768,7 @@ failed:
 }
 
 
-void dtl1_release(dev_link_t *link)
+static void dtl1_release(dev_link_t *link)
 {
        dtl1_info_t *info = link->priv;
 
@@ -784,7 +785,7 @@ void dtl1_release(dev_link_t *link)
 }
 
 
-int dtl1_event(event_t event, int priority, event_callback_args_t *args)
+static int dtl1_event(event_t event, int priority, event_callback_args_t *args)
 {
        dev_link_t *link = args->client_data;
        dtl1_info_t *info = link->priv;
index d1df4ad..3b9f7a5 100644 (file)
@@ -338,7 +338,7 @@ static struct miscdevice hci_vhci_miscdev=
         &hci_vhci_fops
 };
 
-int __init hci_vhci_init(void)
+static int __init hci_vhci_init(void)
 {
        BT_INFO("VHCI driver ver %s", VERSION);
 
@@ -350,7 +350,7 @@ int __init hci_vhci_init(void)
        return 0;
 }
 
-void hci_vhci_cleanup(void)
+static void hci_vhci_cleanup(void)
 {
        misc_deregister(&hci_vhci_miscdev);
 }
index 5c484f3..4a83517 100644 (file)
@@ -8,6 +8,7 @@
 obj-$(CONFIG_BLK_DEV_IDECD)    +=              cdrom.o
 obj-$(CONFIG_BLK_DEV_SR)       +=              cdrom.o
 obj-$(CONFIG_PARIDE_PCD)       +=              cdrom.o
+obj-$(CONFIG_CDROM_PKTCDVD)    +=              cdrom.o
 
 obj-$(CONFIG_AZTCD)            += aztcd.o
 obj-$(CONFIG_CDU31A)           += cdu31a.o     cdrom.o
index 8846749..8b4a2d4 100644 (file)
@@ -1161,11 +1161,11 @@ static void EvaluateStatus(int st)
        return;
 }
 /*==========================================================================*/
+static int cmd_out_T(void);
+
 static int get_state_T(void)
 {
        int i;
-       
-       static int cmd_out_T(void);
 
        clr_cmdbuf();
        current_drive->n_bytes=1;
@@ -1308,13 +1308,14 @@ static int cc_ReadError(void)
        return (i);
 }
 /*==========================================================================*/
+static int cc_DriveReset(void);
+
 static int cmd_out_T(void)
 {
 #undef CMDT_TRIES
 #define CMDT_TRIES 1000
 #define TEST_FALSE_FF 1
-       
-       static int cc_DriveReset(void);
+
        int i, j, l=0, m, ntries;
        unsigned long flags;
 
index ef1fa6d..471748a 100644 (file)
@@ -627,8 +627,8 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
                DBG("client vm_ops=%p", kerninfo.vm_ops);
                if (kerninfo.vm_ops) {
                        vma->vm_ops = kerninfo.vm_ops;
-               } else if (remap_page_range(vma, vma->vm_start, 
-                                           (kerninfo.aper_base + offset),
+               } else if (remap_pfn_range(vma, vma->vm_start,
+                               (kerninfo.aper_base + offset) >> PAGE_SHIFT,
                                            size, vma->vm_page_prot)) {
                        goto out_again;
                }
@@ -643,8 +643,8 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
                DBG("controller vm_ops=%p", kerninfo.vm_ops);
                if (kerninfo.vm_ops) {
                        vma->vm_ops = kerninfo.vm_ops;
-               } else if (remap_page_range(vma, vma->vm_start, 
-                                           kerninfo.aper_base,
+               } else if (remap_pfn_range(vma, vma->vm_start,
+                                           kerninfo.aper_base >> PAGE_SHIFT,
                                            size, vma->vm_page_prot)) {
                        goto out_again;
                }
index f11cf4e..1dc4259 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/delay.h>
 
 #undef SERIAL_PARANOIA_CHECK
 #define SERIAL_DO_RESTART
@@ -83,14 +84,13 @@ static char *serial_version = "4.30";
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/bitops.h>
 
 #include <asm/setup.h>
 
 #include <asm/system.h>
 
 #include <asm/irq.h>
-#include <asm/bitops.h>
 
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
@@ -645,7 +645,7 @@ static int startup(struct async_struct * info)
        /*
         * and set the speed of the serial port
         */
-       change_speed(info, 0);
+       change_speed(info, NULL);
 
        info->flags |= ASYNC_INITIALIZED;
        local_irq_restore(flags);
@@ -691,7 +691,7 @@ static void shutdown(struct async_struct * info)
 
        if (info->xmit.buf) {
                free_page((unsigned long) info->xmit.buf);
-               info->xmit.buf = 0;
+               info->xmit.buf = NULL;
        }
 
        info->IER = 0;
@@ -907,8 +907,7 @@ static void rs_flush_chars(struct tty_struct *tty)
        local_irq_restore(flags);
 }
 
-static int rs_write(struct tty_struct * tty, int from_user,
-                   const unsigned char *buf, int count)
+static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count)
 {
        int     c, ret = 0;
        struct async_struct *info = (struct async_struct *)tty->driver_data;
@@ -921,57 +920,25 @@ static int rs_write(struct tty_struct * tty, int from_user,
                return 0;
 
        local_save_flags(flags);
-       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;
-
-                       c -= copy_from_user(tmp_buf, buf, c);
-                       if (!c) {
-                               if (!ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-                       local_irq_disable();
-                       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));
-                       local_irq_restore(flags);
-                       buf += c;
-                       count -= c;
-                       ret += c;
-               }
-               up(&tmp_buf_sem);
-       } else {
-               local_irq_disable();
-               while (1) {
-                       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;
+       local_irq_disable();
+       while (1) {
+               c = CIRC_SPACE_TO_END(info->xmit.head,
+                                     info->xmit.tail,
+                                     SERIAL_XMIT_SIZE);
+               if (count < c)
+                       c = count;
+               if (c <= 0) {
+                       break;
                }
-               local_irq_restore(flags);
+               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;
        }
+       local_irq_restore(flags);
+
        if (info->xmit.head != info->xmit.tail
            && !tty->stopped
            && !tty->hw_stopped
@@ -1205,7 +1172,7 @@ check_and_exit:
                                info->tty->alt_speed = 230400;
                        if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
                                info->tty->alt_speed = 460800;
-                       change_speed(info, 0);
+                       change_speed(info, NULL);
                }
        } else
                retval = startup(info);
@@ -1560,11 +1527,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
-       info->tty = 0;
+       info->tty = NULL;
        if (info->blocked_open) {
                if (info->close_delay) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(info->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
                }
                wake_up_interruptible(&info->open_wait);
        }
@@ -1622,8 +1588,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
                printk("serdatr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(char_time);
+               msleep_interruptible(jiffies_to_msecs(char_time));
                if (signal_pending(current))
                        break;
                if (timeout && time_after(jiffies, orig_jiffies + timeout))
@@ -1653,7 +1618,7 @@ static void rs_hangup(struct tty_struct *tty)
        info->event = 0;
        state->count = 0;
        info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->tty = 0;
+       info->tty = NULL;
        wake_up_interruptible(&info->open_wait);
 }
 
@@ -1909,7 +1874,7 @@ static inline int line_info(char *buf, struct serial_state *state)
                info->magic = SERIAL_MAGIC;
                info->flags = state->flags;
                info->quot = 0;
-               info->tty = 0;
+               info->tty = NULL;
        }
        local_irq_save(flags);
        status = ciab.pra;
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);
index b3289d9..452d45c 100644 (file)
@@ -43,9 +43,9 @@
 #include <linux/slab.h>
 #include <linux/kbd_kern.h>
 #include <linux/smp_lock.h>
+#include <linux/bitops.h>
 
 #include <asm/keyboard.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 #include <asm/system.h>
index 0f13bef..6025e18 100644 (file)
@@ -218,7 +218,7 @@ void epca_setup(char *, int *);
 void console_print(const char *);
 
 static int get_termio(struct tty_struct *, struct termio __user *);
-static int pc_write(struct tty_struct *, int, const unsigned char *, int);
+static int pc_write(struct tty_struct *, const unsigned char *, int);
 int pc_init(void);
 
 #ifdef ENABLE_PCI
@@ -561,8 +561,7 @@ static void pc_close(struct tty_struct * tty, struct file * filp)
 
                        if (ch->close_delay) 
                        {
-                               current->state = TASK_INTERRUPTIBLE;
-                               schedule_timeout(ch->close_delay);
+                               msleep_interruptible(jiffies_to_msecs(ch->close_delay));
                        }
 
                        wake_up_interruptible(&ch->open_wait);
@@ -670,7 +669,7 @@ static void pc_hangup(struct tty_struct *tty)
 
 /* ------------------ Begin pc_write  ------------------------- */
 
-static int pc_write(struct tty_struct * tty, int from_user,
+static int pc_write(struct tty_struct * tty,
                     const unsigned char *buf, int bytesAvailable)
 { /* Begin pc_write */
 
@@ -708,162 +707,6 @@ static int pc_write(struct tty_struct * tty, int from_user,
        bc   = ch->brdchan;
        size = ch->txbufsize;
 
-       if (from_user) 
-       { /* Begin from_user */
-
-               save_flags(flags);
-               cli();
-
-               globalwinon(ch);
-
-               /* -----------------------------------------------------------------    
-                       Anding against size will wrap the pointer back to its beginning 
-                       position if it is necessary.  This will only work if size is
-                       a power of 2 which should always be the case.  Size is determined 
-                       by the cards on board FEP/OS.
-               -------------------------------------------------------------------- */ 
-
-               /* head refers to the next empty location in which data may be stored */ 
-
-               head = bc->tin & (size - 1);
-
-               /* tail refers to the next data byte to be transmitted */ 
-
-               tail = bc->tout;
-
-               /* Consider changing this to a do statement to make sure */
-
-               if (tail != bc->tout)
-                       tail = bc->tout;
-
-               /* ------------------------------------------------------------------   
-                       Anding against size will wrap the pointer back to its beginning 
-                       position if it is necessary.  This will only work if size is
-                       a power of 2 which should always be the case.  Size is determined 
-                       by the cards on board FEP/OS.
-               --------------------------------------------------------------------- */        
-
-               tail &= (size - 1);
-
-               /* -----------------------------------------------------------------
-                       Two situations can affect how space in the transmit buffer
-                       is calculated.  You can have a situation where the transmit
-                       in pointer (tin) head has wrapped around and actually has a 
-                       lower address than the transmit out pointer (tout) tail; or
-                       the transmit in pointer (tin) head will not be wrapped around
-                       yet, and have a higher address than the transmit out pointer
-                       (tout) tail.  Obviously space available in the transmit buffer
-                       is calculated differently for each case.
-
-                       Example 1:
-                       
-                       Consider a 10 byte buffer where head is a pointer to the next
-                       empty location in the buffer and tail is a pointer to the next 
-                       byte to transmit.  In this example head will not have wrapped 
-                       around and therefore head > tail.  
-
-                       0      1      2      3      4      5      6      7      8      9   
-                               tail                               head
-
-                       The above diagram shows that buffer locations 2,3,4,5 and 6 have
-                       data to be transmitted, while head points at the next empty
-                       location.  To calculate how much space is available first we have
-                       to determine if the head pointer (tin) has wrapped.  To do this
-                       compare the head pointer to the tail pointer,  If head is equal
-                       or greater than tail; then it has not wrapped; and the space may
-                       be calculated by subtracting tail from head and then subtracting
-                       that value from the buffers size.  A one is subtracted from the
-                       new value to indicate how much space is available between the 
-                       head pointer and end of buffer; as well as the space between the
-                       beginning of the buffer and the tail.  If the head is not greater
-                       or equal to the tail this indicates that the head has wrapped
-                       around to the beginning of the buffer.  To calculate the space 
-                       available in this case simply subtract head from tail.  This new 
-                       value minus one represents the space available betwwen the head 
-                       and tail pointers.  In this example head (7) is greater than tail (2)
-                       and therefore has not wrapped around.  We find the space by first
-                       subtracting tail from head (7-2=5).  We then subtract this value
-                       from the buffer size of ten and subtract one (10-5-1=4).  The space
-                       remaining is 4 bytes. 
-
-                       Example 2:
-                       
-                       Consider a 10 byte buffer where head is a pointer to the next
-                       empty location in the buffer and tail is a pointer to the next 
-                       byte to transmit.  In this example head will wrapped around and 
-                       therefore head < tail.  
-
-                       0      1      2      3      4      5      6      7      8      9   
-                               head                               tail
-
-                       The above diagram shows that buffer locations 7,8,9,0 and 1 have
-                       data to be transmitted, while head points at the next empty
-                       location.  To find the space available we compare head to tail.  If
-                       head is not equal to, or greater than tail this indicates that head
-                       has wrapped around. In this case head (2) is not equal to, or
-                       greater than tail (7) and therefore has already wrapped around.  To
-                       calculate the available space between the two pointers we subtract
-                       head from tail (7-2=5).  We then subtract one from this new value
-                       (5-1=4).  We have 5 bytes empty remaining in the buffer.  Unlike the
-                       previous example these five bytes are located between the head and
-                       tail pointers. 
-
-               ----------------------------------------------------------------------- */
-
-               dataLen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
-
-               /* ----------------------------------------------------------------------
-                       In this case bytesAvailable has been passed into pc_write and
-                       represents the amount of data that needs to be written.  dataLen
-                       represents the amount of space available on the card.  Whichever
-                       value is smaller will be the amount actually written. 
-                       bytesAvailable will then take on this newly calculated value.
-               ---------------------------------------------------------------------- */
-
-               bytesAvailable = min(dataLen, bytesAvailable);
-
-               /* First we read the data in from the file system into a temp buffer */
-
-               memoff(ch);
-               restore_flags(flags);
-
-               if (bytesAvailable) 
-               { /* Begin bytesAvailable */
-                       /* ---------------------------------------------------------------
-                               The below function reads data from user memory.  This routine
-                               can not be used in an interrupt routine. (Because it may 
-                               generate a page fault)  It can only be called while we can the
-                               user context is accessible. 
-
-                               The prototype is :
-                               inline void copy_from_user(void * to, const void * from,
-                                                         unsigned long count);
-
-                               I also think (Check hackers guide) that optimization must
-                               be turned ON.  (Which sounds strange to me...)
-
-                               Remember copy_from_user WILL generate a page fault if the
-                               user memory being accessed has been swapped out.  This can
-                               cause this routine to temporarily sleep while this page
-                               fault is occurring.
-                       
-                       ----------------------------------------------------------------- */
-
-                       if (copy_from_user(ch->tmp_buf, buf,
-                                          bytesAvailable))
-                               return -EFAULT;
-               } /* End bytesAvailable */
-
-               /* ------------------------------------------------------------------ 
-                       Set buf to this address for the moment.  tmp_buf was allocated in
-                       post_fep_init.
-               --------------------------------------------------------------------- */
-               buf = ch->tmp_buf;
-
-       } /* End from_user */
-
-       /* All data is now local */
-
        amountCopied = 0;
        save_flags(flags);
        cli();
@@ -954,7 +797,7 @@ static void pc_put_char(struct tty_struct *tty, unsigned char c)
 { /* Begin pc_put_char */
 
    
-       pc_write(tty, 0, &c, 1);
+       pc_write(tty, &c, 1);
        return;
 
 } /* End pc_put_char */
@@ -3933,23 +3776,12 @@ MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
 
 int __init init_PCI (void)
 { /* Begin init_PCI */
-       
-       int pci_count;
-       
        memset (&epca_driver, 0, sizeof (epca_driver));
        epca_driver.name = "epca";
        epca_driver.id_table = epca_pci_tbl;
        epca_driver.probe = epca_init_one;
 
-       pci_count = pci_register_driver (&epca_driver);
-       
-       if (pci_count <= 0) {
-               pci_unregister_driver (&epca_driver);
-               pci_count = 0;
-       }
-
-       return(pci_count);
-
+       return pci_register_driver(&epca_driver);
 } /* End init_PCI */
 
 #endif /* ENABLE_PCI */
index ee1c983..52205ef 100644 (file)
@@ -149,7 +149,7 @@ struct board_info
        ushort numports;
        unchar *port;
        unchar *membase;
-       unchar *re_map_port;
+       unchar __iomem *re_map_port;
        unchar *re_map_membase;
        ulong  memory_seg;
        void ( * memwinon )     (struct board_info *, unsigned int) ;
index 1d4619a..f83b60c 100644 (file)
@@ -726,9 +726,12 @@ int ftape_mmap(struct vm_area_struct *vma)
                ftape_reset_buffer();
        }
        for (i = 0; i < num_buffers; i++) {
-               TRACE_CATCH(remap_page_range(vma, vma->vm_start +
+               unsigned long pfn;
+
+               pfn = virt_to_phys(ft_buffer[i]->address) >> PAGE_SHIFT;
+               TRACE_CATCH(remap_pfn_range(vma, vma->vm_start +
                                             i * FT_BUFF_SIZE,
-                                            virt_to_phys(ft_buffer[i]->address),
+                                            pfn,
                                             FT_BUFF_SIZE,
                                             vma->vm_page_prot),
                            _res = -EAGAIN);
index bd3b2f1..b7910d4 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/system.h>
 #include <linux/ioctl.h>
 #include <linux/mtio.h>
+#include <linux/delay.h>
 
 #include <linux/ftape.h>
 #include <linux/qic117.h>
@@ -96,19 +97,12 @@ void ftape_sleep(unsigned int time)
                timeout = ticks;
                save_flags(flags);
                sti();
-               set_current_state(TASK_INTERRUPTIBLE);
-               do {
-                       /*  Mmm. Isn't current->blocked == 0xffffffff ?
-                        */
-                       if (signal_pending(current)) {
-                               TRACE(ft_t_err,
-                                     "awoken by non-blocked signal :-(");
-                               break;  /* exit on signal */
-                       }
-                       while (current->state != TASK_RUNNING) {
-                               timeout = schedule_timeout(timeout);
-                       }
-               } while (timeout);
+               msleep_interruptible(jiffies_to_msecs(timeout));
+               /*  Mmm. Isn't current->blocked == 0xffffffff ?
+                */
+               if (signal_pending(current)) {
+                       TRACE(ft_t_err, "awoken by non-blocked signal :-(");
+               }
                restore_flags(flags);
        }
        TRACE_EXIT;
index 3d64839..ec4fdaa 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #include <linux/zftape.h>
 
@@ -119,8 +120,7 @@ void *zft_kmalloc(size_t size)
        void *new;
 
        while ((new = kmalloc(size, GFP_KERNEL)) == NULL) {
-               current->state   = TASK_INTERRUPTIBLE;
-               schedule_timeout(HZ/10);
+               msleep_interruptible(100);
        }
        memset(new, 0, size);
        used_memory += size;
index 45bc1be..d95ad27 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/mm.h>
 #include <linux/generic_serial.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
 
@@ -57,7 +58,7 @@ static int gs_debug;
 
 #define RS_EVENT_WRITE_WAKEUP  1
 
-MODULE_PARM(gs_debug, "i");
+module_param(gs_debug, int, 0644);
 
 
 void gs_put_char(struct tty_struct * tty, unsigned char ch)
@@ -102,7 +103,7 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch)
 >       -3- Other processes that are also trying to do a "write". 
 */
 
-int gs_write(struct tty_struct * tty, int from_user, 
+int gs_write(struct tty_struct * tty, 
                     const unsigned char *buf, int count)
 {
        struct gs_port *port;
@@ -143,15 +144,8 @@ int gs_write(struct tty_struct * tty, int from_user,
  
                /* Can't copy more? break out! */
                if (c <= 0) break;
-               if (from_user) {
-                       if (copy_from_user (port->xmit_buf + port->xmit_head, 
-                                           buf, c)) {
-                               up (& port->port_write_sem);
-                               return -EFAULT;
-                       }
 
-               } else
-                       memcpy (port->xmit_buf + port->xmit_head, buf, c);
+               memcpy (port->xmit_buf + port->xmit_head, buf, c);
 
                port -> xmit_cnt += c;
                port -> xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE -1);
@@ -182,7 +176,7 @@ int gs_write(struct tty_struct * tty, int from_user,
 >       -3- Other processes that are also trying to do a "write". 
 */
 
-int gs_write(struct tty_struct * tty, int from_user, 
+int gs_write(struct tty_struct * tty,
                     const unsigned char *buf, int count)
 {
        struct gs_port *port;
@@ -215,79 +209,35 @@ int gs_write(struct tty_struct * tty, int from_user,
                return -EIO;
 
        save_flags(flags);
-       if (from_user) {
-               down(&tmp_buf_sem);
-               while (1) {
-                       c = count;
-
-                       /* This is safe because we "OWN" the "head". Noone else can 
-                          change the "head": we own the port_write_sem. */
-                       /* Don't overrun the end of the buffer */
-                       t = SERIAL_XMIT_SIZE - port->xmit_head;
-                       if (t < c) c = t;
-                       /* This is safe because the xmit_cnt can only decrease. This 
-                          would increase "t", so we might copy too little chars. */
-                       /* Don't copy past the "head" of the buffer */
-                       t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
-                       if (t < c) c = t;        
-
-                       /* Can't copy more? break out! */
-                       if (c <= 0) break;
-
-                       c -= copy_from_user(tmp_buf, buf, c);
-                       if (!c) {
-                               if (!total)
-                                       total = -EFAULT;
-                               break;
-                       }
-                       cli();
-                       t = SERIAL_XMIT_SIZE - port->xmit_head;
-                       if (t < c) c = t;
-                       t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
-                       if (t < c) c = t;
-
-                       memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
-                       port->xmit_head = ((port->xmit_head + c) &
-                                          (SERIAL_XMIT_SIZE-1));
-                       port->xmit_cnt += c;
-                       restore_flags(flags);
-                       buf += c;
-                       count -= c;
-                       total += c;
-               }
-               up(&tmp_buf_sem);
-       } else {
-               while (1) {
-                       cli();
-                       c = count;
-
-                       /* This is safe because we "OWN" the "head". Noone else can 
-                          change the "head": we own the port_write_sem. */
-                       /* Don't overrun the end of the buffer */
-                       t = SERIAL_XMIT_SIZE - port->xmit_head;
-                       if (t < c) c = t;
-                       /* This is safe because the xmit_cnt can only decrease. This 
-                          would increase "t", so we might copy too little chars. */
-                       /* Don't copy past the "head" of the buffer */
-                       t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
-                       if (t < c) c = t;
-                       /* Can't copy more? break out! */
-                       if (c <= 0) {
-                               restore_flags(flags);
-                               break;
-                       }
-                       memcpy(port->xmit_buf + port->xmit_head, buf, c);
-                       port->xmit_head = ((port->xmit_head + c) &
-                                          (SERIAL_XMIT_SIZE-1));
-                       port->xmit_cnt += c;
+       while (1) {
+               cli();
+               c = count;
+
+               /* This is safe because we "OWN" the "head". Noone else can 
+                  change the "head": we own the port_write_sem. */
+               /* Don't overrun the end of the buffer */
+               t = SERIAL_XMIT_SIZE - port->xmit_head;
+               if (t < c) c = t;
+
+               /* This is safe because the xmit_cnt can only decrease. This 
+                  would increase "t", so we might copy too little chars. */
+               /* Don't copy past the "head" of the buffer */
+               t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+               if (t < c) c = t;
+
+               /* Can't copy more? break out! */
+               if (c <= 0) {
                        restore_flags(flags);
-                       buf += c;
-                       count -= c;
-                       total += c;
+                       break;
                }
+               memcpy(port->xmit_buf + port->xmit_head, buf, c);
+               port->xmit_head = ((port->xmit_head + c) &
+                                  (SERIAL_XMIT_SIZE-1));
+               port->xmit_cnt += c;
+               restore_flags(flags);
+               buf += c;
+               count -= c;
+               total += c;
        }
 
        if (port->xmit_cnt && 
@@ -399,8 +349,7 @@ static int gs_wait_tx_flushed (void * ptr, int timeout)
                gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies "
                            "(%d chars).\n", jiffies_to_transmit, charsleft); 
 
-               set_current_state (TASK_INTERRUPTIBLE);
-               schedule_timeout(jiffies_to_transmit);
+               msleep_interruptible(jiffies_to_msecs(jiffies_to_transmit));
                if (signal_pending (current)) {
                        gs_dprintk (GS_DEBUG_FLUSH, "Signal pending. Bombing out: "); 
                        rv = -EINTR;
@@ -767,8 +716,7 @@ void gs_close(struct tty_struct * tty, struct file * filp)
 
        if (port->blocked_open) {
                if (port->close_delay) {
-                       set_current_state (TASK_INTERRUPTIBLE);
-                       schedule_timeout(port->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(port->close_delay));
                }
                wake_up_interruptible(&port->open_wait);
        }
index 22d46cd..ca7d88a 100644 (file)
 #include <linux/wait.h>
 #include <linux/bcd.h>
 #include <linux/seq_file.h>
+#include <linux/bitops.h>
 
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/div64.h>
 
 #include <linux/acpi.h>
@@ -76,6 +76,7 @@ struct hpet_dev {
 struct hpets {
        struct hpets *hp_next;
        struct hpet __iomem *hp_hpet;
+       struct time_interpolator *hp_interpolator;
        unsigned long hp_period;
        unsigned long hp_delta;
        unsigned int hp_ntimer;
@@ -273,9 +274,9 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        addr = __pa(addr);
 
-       if (remap_page_range
-           (vma, vma->vm_start, addr, PAGE_SIZE, vma->vm_page_prot)) {
-               printk(KERN_ERR "remap_page_range failed in hpet.c\n");
+       if (remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
+                                       PAGE_SIZE, vma->vm_page_prot)) {
+               printk(KERN_ERR "remap_pfn_range failed in hpet.c\n");
                return -EAGAIN;
        }
 
@@ -660,15 +661,6 @@ int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
        return hpet_ioctl_common(devp, cmd, arg, 1);
 }
 
-#ifdef CONFIG_TIME_INTERPOLATION
-
-static struct time_interpolator hpet_interpolator = {
-       .source = TIME_SOURCE_MMIO64,
-       .shift = 10
-};
-
-#endif
-
 static ctl_table hpet_table[] = {
        {
         .ctl_name = 1,
@@ -705,6 +697,28 @@ static ctl_table dev_root[] = {
 
 static struct ctl_table_header *sysctl_header;
 
+static void hpet_register_interpolator(struct hpets *hpetp)
+{
+#ifdef CONFIG_TIME_INTERPOLATION
+       struct time_interpolator *ti;
+
+       ti = kmalloc(sizeof(*ti), GFP_KERNEL);
+       if (!ti)
+               return;
+
+       memset(ti, 0, sizeof(*ti));
+       ti->source = TIME_SOURCE_MMIO64;
+       ti->shift = 10;
+       ti->addr = &hpetp->hp_hpet->hpet_mc;
+       ti->frequency = hpet_time_div(hpets->hp_period);
+       ti->drift = ti->frequency * HPET_DRIFT / 1000000;
+       ti->mask = -1;
+
+       hpetp->hp_interpolator = ti;
+       register_time_interpolator(ti);
+#endif
+}
+
 /*
  * Adjustment for when arming the timer with
  * initial conditions.  That is, main counter
@@ -712,7 +726,7 @@ static struct ctl_table_header *sysctl_header;
  */
 #define        TICK_CALIBRATE  (1000UL)
 
-static unsigned long __init hpet_calibrate(struct hpets *hpetp)
+static unsigned long hpet_calibrate(struct hpets *hpetp)
 {
        struct hpet_timer __iomem *timer = NULL;
        unsigned long t, m, count, i, flags, start;
@@ -749,7 +763,7 @@ static unsigned long __init hpet_calibrate(struct hpets *hpetp)
        return (m - start) / i;
 }
 
-int __init hpet_alloc(struct hpet_data *hdp)
+int hpet_alloc(struct hpet_data *hdp)
 {
        u64 cap, mcfg;
        struct hpet_dev *devp;
@@ -757,7 +771,7 @@ int __init hpet_alloc(struct hpet_data *hdp)
        struct hpets *hpetp;
        size_t siz;
        struct hpet __iomem *hpet;
-       static struct hpets *last __initdata = (struct hpets *)0;
+       static struct hpets *last = (struct hpets *)0;
        unsigned long ns;
 
        /*
@@ -810,8 +824,9 @@ int __init hpet_alloc(struct hpet_data *hdp)
        hpetp->hp_period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >>
            HPET_COUNTER_CLK_PERIOD_SHIFT;
 
-       printk(KERN_INFO "hpet%d: at MMIO 0x%p, IRQ%s",
-               hpetp->hp_which, hpet, hpetp->hp_ntimer > 1 ? "s" : "");
+       printk(KERN_INFO "hpet%d: at MMIO 0x%lx, IRQ%s",
+               hpetp->hp_which, hdp->hd_phys_address,
+               hpetp->hp_ntimer > 1 ? "s" : "");
        for (i = 0; i < hpetp->hp_ntimer; i++)
                printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
        printk("\n");
@@ -854,11 +869,12 @@ int __init hpet_alloc(struct hpet_data *hdp)
        }
 
        hpetp->hp_delta = hpet_calibrate(hpetp);
+       hpet_register_interpolator(hpetp);
 
        return 0;
 }
 
-static acpi_status __init hpet_resources(struct acpi_resource *res, void *data)
+static acpi_status hpet_resources(struct acpi_resource *res, void *data)
 {
        struct hpet_data *hdp;
        acpi_status status;
@@ -873,6 +889,7 @@ static acpi_status __init hpet_resources(struct acpi_resource *res, void *data)
                unsigned long size;
 
                size = addr.max_address_range - addr.min_address_range + 1;
+               hdp->hd_phys_address = addr.min_address_range;
                hdp->hd_address = ioremap(addr.min_address_range, size);
 
                for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
@@ -898,7 +915,7 @@ static acpi_status __init hpet_resources(struct acpi_resource *res, void *data)
        return AE_OK;
 }
 
-static int __init hpet_acpi_add(struct acpi_device *device)
+static int hpet_acpi_add(struct acpi_device *device)
 {
        acpi_status result;
        struct hpet_data data;
@@ -920,9 +937,10 @@ static int __init hpet_acpi_add(struct acpi_device *device)
        return hpet_alloc(&data);
 }
 
-static int __init hpet_acpi_remove(struct acpi_device *device, int type)
+static int hpet_acpi_remove(struct acpi_device *device, int type)
 {
-       return 0;
+       /* XXX need to unregister interpolator, dealloc mem, etc */
+       return -EINVAL;
 }
 
 static struct acpi_driver hpet_acpi_driver = {
@@ -938,37 +956,32 @@ static struct miscdevice hpet_misc = { HPET_MINOR, "hpet", &hpet_fops };
 
 static int __init hpet_init(void)
 {
-       (void)acpi_bus_register_driver(&hpet_acpi_driver);
+       int result;
 
-       if (hpets) {
-               if (misc_register(&hpet_misc))
-                       return -ENODEV;
+       result = misc_register(&hpet_misc);
+       if (result < 0)
+               return -ENODEV;
 
-               sysctl_header = register_sysctl_table(dev_root, 0);
+       sysctl_header = register_sysctl_table(dev_root, 0);
 
-#ifdef CONFIG_TIME_INTERPOLATION
-               {
-                       struct hpet *hpet;
-
-                       hpet = hpets->hp_hpet;
-                       hpet_interpolator.addr = &hpets->hp_hpet->hpet_mc;
-                       hpet_interpolator.frequency = hpet_time_div(hpets->hp_period);
-                       hpet_interpolator.drift = hpet_interpolator.frequency *
-                           HPET_DRIFT / 1000000;
-                       register_time_interpolator(&hpet_interpolator);
-               }
-#endif
-               return 0;
-       } else
-               return -ENODEV;
+       result = acpi_bus_register_driver(&hpet_acpi_driver);
+       if (result < 0) {
+               if (sysctl_header)
+                       unregister_sysctl_table(sysctl_header);
+               misc_deregister(&hpet_misc);
+               return result;
+       }
+
+       return 0;
 }
 
 static void __exit hpet_exit(void)
 {
        acpi_bus_unregister_driver(&hpet_acpi_driver);
 
-       if (hpets)
+       if (sysctl_header)
                unregister_sysctl_table(sysctl_header);
+       misc_deregister(&hpet_misc);
 
        return;
 }
index 3c0af2c..9d7682c 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/tty_flip.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/hvconsole.h>
 #include <asm/vio.h>
@@ -44,7 +45,7 @@
 #define HVC_MAJOR      229
 #define HVC_MINOR      0
 
-#define TIMEOUT                ((HZ + 99) / 100)
+#define TIMEOUT                (10)
 
 /*
  * Wait this long per iteration while trying to push buffered data to the
@@ -220,6 +221,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
                spin_unlock_irqrestore(&hp->lock, flags);
                tty->driver_data = NULL;
                kobject_put(kobjp);
+               printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
        }
        /* Force wakeup of the polling thread */
        hvc_kick();
@@ -239,7 +241,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 
        /*
         * No driver_data means that this close was issued after a failed
-        * hvcs_open by the tty layer's release_dev() function and we can just
+        * hvc_open by the tty layer's release_dev() function and we can just
         * exit cleanly because the kobject reference wasn't made.
         */
        if (!tty->driver_data)
@@ -265,13 +267,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
                 */
                tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
 
-               /*
-                * Since the line disc doesn't block writes during tty close
-                * operations we'll set driver_data to NULL and then make sure
-                * to check tty->driver_data for NULL in hvc_write().
-                */
-               tty->driver_data = NULL;
-
                if (irq != NO_IRQ)
                        free_irq(irq, hp);
 
@@ -293,7 +288,21 @@ static void hvc_hangup(struct tty_struct *tty)
        int temp_open_count;
        struct kobject *kobjp;
 
+       if (!hp)
+               return;
+
        spin_lock_irqsave(&hp->lock, flags);
+
+       /*
+        * The N_TTY line discipline has problems such that in a close vs
+        * open->hangup case this can be called after the final close so prevent
+        * that from happening for now.
+        */
+       if (hp->count <= 0) {
+               spin_unlock_irqrestore(&hp->lock, flags);
+               return;
+       }
+
        kobjp = &hp->kobj;
        temp_open_count = hp->count;
        hp->count = 0;
@@ -335,62 +344,6 @@ static void hvc_push(struct hvc_struct *hp)
                hp->do_wakeup = 1;
 }
 
-static inline int __hvc_write_user(struct hvc_struct *hp,
-                                  const unsigned char *buf, int count)
-{
-       char *tbuf, *p;
-       int tbsize, rsize, written = 0;
-       unsigned long flags;
-
-       tbsize = min(count, (int)PAGE_SIZE);
-       if (!(tbuf = kmalloc(tbsize, GFP_KERNEL)))
-               return -ENOMEM;
-
-       while ((rsize = count - written) > 0) {
-               int wsize;
-               if (rsize > tbsize)
-                       rsize = tbsize;
-
-               p = tbuf;
-               rsize -= copy_from_user(p, buf, rsize);
-               if (!rsize) {
-                       if (written == 0)
-                               written = -EFAULT;
-                       break;
-               }
-               buf += rsize;
-
-               spin_lock_irqsave(&hp->lock, flags);
-
-               /* Push pending writes: make some room in buffer */
-               if (hp->n_outbuf > 0)
-                       hvc_push(hp);
-
-               for (wsize = N_OUTBUF - hp->n_outbuf; rsize && wsize;
-                    wsize = N_OUTBUF - hp->n_outbuf) {
-                       if (wsize > rsize)
-                               wsize = rsize;
-                       memcpy(hp->outbuf + hp->n_outbuf, p, wsize);
-                       hp->n_outbuf += wsize;
-                       hvc_push(hp);
-                       rsize -= wsize;
-                       p += wsize;
-                       written += wsize;
-               }
-               spin_unlock_irqrestore(&hp->lock, flags);
-
-               if (rsize)
-                       break;
-
-               if (count < tbsize)
-                       tbsize = count;
-       }
-
-       kfree(tbuf);
-
-       return written;
-}
-
 static inline int __hvc_write_kernel(struct hvc_struct *hp,
                                   const unsigned char *buf, int count)
 {
@@ -417,8 +370,7 @@ static inline int __hvc_write_kernel(struct hvc_struct *hp,
 
        return written;
 }
-static int hvc_write(struct tty_struct *tty, int from_user,
-                    const unsigned char *buf, int count)
+static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        struct hvc_struct *hp = tty->driver_data;
        int written;
@@ -427,10 +379,10 @@ static int hvc_write(struct tty_struct *tty, int from_user,
        if (!hp)
                return -EPIPE;
 
-       if (from_user)
-               written = __hvc_write_user(hp, buf, count);
-       else
-               written = __hvc_write_kernel(hp, buf, count);
+       if (hp->count <= 0)
+               return -EIO;
+
+       written = __hvc_write_kernel(hp, buf, count);
 
        /*
         * Racy, but harmless, kick thread if there is still pending data.
@@ -607,7 +559,7 @@ int khvcd(void *unused)
                        if (poll_mask == 0)
                                schedule();
                        else
-                               schedule_timeout(TIMEOUT);
+                               msleep_interruptible(TIMEOUT);
                }
                __set_current_state(TASK_RUNNING);
        } while (!kthread_should_stop());
@@ -629,7 +581,7 @@ char hvc_driver_name[] = "hvc_console";
 
 static struct vio_device_id hvc_driver_table[] __devinitdata= {
        {"serial", "hvterm1"},
-       { 0, }
+       { NULL, }
 };
 MODULE_DEVICE_TABLE(vio, hvc_driver_table);
 
index 15b1d8c..c605280 100644 (file)
@@ -315,7 +315,7 @@ static void hvcs_throttle(struct tty_struct *tty);
 static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance,
                struct pt_regs *regs);
 
-static int hvcs_write(struct tty_struct *tty, int from_user,
+static int hvcs_write(struct tty_struct *tty,
                const unsigned char *buf, int count);
 static int hvcs_write_room(struct tty_struct *tty);
 static int hvcs_chars_in_buffer(struct tty_struct *tty);
@@ -527,7 +527,7 @@ static int khvcsd(void *unused)
 
 static struct vio_device_id hvcs_driver_table[] __devinitdata= {
        {"serial-server", "hvterm2"},
-       { 0, }
+       { NULL, }
 };
 MODULE_DEVICE_TABLE(vio, hvcs_driver_table);
 
@@ -1183,12 +1183,12 @@ static void hvcs_hangup(struct tty_struct * tty)
  * tty_hangup will allow hvcs_write time to complete execution before it
  * terminates our device.
  */
-static int hvcs_write(struct tty_struct *tty, int from_user,
+static int hvcs_write(struct tty_struct *tty,
                const unsigned char *buf, int count)
 {
        struct hvcs_struct *hvcsd = tty->driver_data;
        unsigned int unit_address;
-       unsigned char *charbuf;
+       const unsigned char *charbuf;
        unsigned long flags;
        int total_sent = 0;
        int tosend = 0;
@@ -1208,21 +1208,7 @@ static int hvcs_write(struct tty_struct *tty, int from_user,
                count = HVCS_MAX_FROM_USER;
        }
 
-       if (!from_user)
-               charbuf = (unsigned char *)buf;
-       else {
-               charbuf = kmalloc(count, GFP_KERNEL);
-               if (!charbuf) {
-                       printk(KERN_WARNING "HVCS: write -ENOMEM.\n");
-                       return -ENOMEM;
-               }
-
-               if (copy_from_user(charbuf, buf, count)) {
-                       kfree(charbuf);
-                       printk(KERN_WARNING "HVCS: write -EFAULT.\n");
-                       return -EFAULT;
-               }
-       }
+       charbuf = buf;
 
        spin_lock_irqsave(&hvcsd->lock, flags);
 
@@ -1234,8 +1220,6 @@ static int hvcs_write(struct tty_struct *tty, int from_user,
         */
        if (hvcsd->open_count <= 0) {
                spin_unlock_irqrestore(&hvcsd->lock, flags);
-               if (from_user)
-                       kfree(charbuf);
                return -ENODEV;
        }
 
@@ -1292,8 +1276,6 @@ static int hvcs_write(struct tty_struct *tty, int from_user,
        }
 
        spin_unlock_irqrestore(&hvcsd->lock, flags);
-       if (from_user)
-               kfree(charbuf);
 
        if (result == -1)
                return -EIO;
index ad4a967..947a3c7 100644 (file)
@@ -65,18 +65,20 @@ static char product_name [48] = "?";
 static char bios_version [4]  = "?";
 static char serial_number[16] = "?";
 
-static int force = 0;
-static int restricted = 0;
-static int power_status = 0;
-
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
 MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
 MODULE_LICENSE("GPL");
-MODULE_PARM(force, "i");
-MODULE_PARM(restricted, "i");
-MODULE_PARM(power_status, "i");
+
+static int force;
+module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Force loading without checking for supported models");
+
+static int restricted;
+module_param(restricted, bool, 0);
 MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
+
+static int power_status;
+module_param(power_status, bool, 0600);
 MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
 static ssize_t i8k_read(struct file *, char __user *, size_t, loff_t *);
index 8e62d6d..6cd12f2 100644 (file)
@@ -38,11 +38,11 @@ static int poll_only = 0;
 
 MODULE_AUTHOR("Doug McNash");
 MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
-MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
+module_param_array(irq, int, NULL, 0);
 MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
-MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
+module_param_array(io, int, NULL, 0);
 MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
-MODULE_PARM(poll_only,"1i");
+module_param(poll_only, bool, 0);
 MODULE_PARM_DESC(poll_only,"Do not use card interrupts");
 
 
index b454bf2..b3f40fe 100644 (file)
@@ -1124,11 +1124,10 @@ static void isicom_close(struct tty_struct * tty, struct file * filp)
        port->tty = NULL;
        if (port->blocked_open) {
                if (port->close_delay) {
-                       set_current_state(TASK_INTERRUPTIBLE);
 #ifdef ISICOM_DEBUG                    
                        printk(KERN_DEBUG "ISICOM: scheduling until time out.\n");
 #endif                 
-                       schedule_timeout(port->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(port->close_delay));
                }
                wake_up_interruptible(&port->open_wait);
        }       
@@ -1141,7 +1140,7 @@ static void isicom_close(struct tty_struct * tty, struct file * filp)
 }
 
 /* write et all */
-static int isicom_write(struct tty_struct * tty, int from_user,
+static int isicom_write(struct tty_struct * tty,
                        const unsigned char * buf, int count)
 {
        struct isi_port * port = (struct isi_port *) tty->driver_data;
@@ -1156,8 +1155,6 @@ static int isicom_write(struct tty_struct * tty, int from_user,
        
        if (!tty || !port->xmit_buf || !tmp_buf)
                return 0;
-       if (from_user)
-               down(&tmp_buf_sem); /* acquire xclusive access to tmp_buf */
                
        save_flags(flags);
        while(1) {      
@@ -1167,24 +1164,7 @@ static int isicom_write(struct tty_struct * tty, int from_user,
                if (cnt <= 0) 
                        break;
                
-               if (from_user) {
-                       /* the following may block for paging... hence 
-                          enabling interrupts but tx routine may have 
-                          created more space in xmit_buf when the ctrl 
-                          gets back here  */
-                       sti(); 
-                       if (copy_from_user(tmp_buf, buf, cnt)) {
-                               up(&tmp_buf_sem);
-                               restore_flags(flags);
-                               return -EFAULT;
-                       }
-                       cli();
-                       cnt = min_t(int, cnt, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                                 SERIAL_XMIT_SIZE - port->xmit_head));
-                       memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt);
-               }       
-               else
-                       memcpy(port->xmit_buf + port->xmit_head, buf, cnt);
+               memcpy(port->xmit_buf + port->xmit_head, buf, cnt);
                port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1);
                port->xmit_cnt += cnt;
                restore_flags(flags);
@@ -1192,8 +1172,6 @@ static int isicom_write(struct tty_struct * tty, int from_user,
                count -= cnt;
                total += cnt;
        }               
-       if (from_user)
-               up(&tmp_buf_sem);
        if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
                port->status |= ISI_TXOK;
        restore_flags(flags);
@@ -1795,9 +1773,9 @@ static int irq[4];
 MODULE_AUTHOR("MultiTech");
 MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
 MODULE_LICENSE("GPL");
-MODULE_PARM(io, "1-4i");
+module_param_array(io, int, NULL, 0);
 MODULE_PARM_DESC(io, "I/O ports for the cards");
-MODULE_PARM(irq, "1-4i");
+module_param_array(irq, int, NULL, 0);
 MODULE_PARM_DESC(irq, "Interrupts for the cards");
 
 int init_module(void)
index 20aa170..c254bf7 100644 (file)
@@ -13,6 +13,9 @@
  *
  * 11/01/01 - jbarnes - initial revision
  * 9/10/04 - Christoph Lameter - remove interrupt support for kernel inclusion
+ * 10/1/04 - Christoph Lameter - provide posix clock CLOCK_SGI_CYCLE
+ * 10/13/04 - Christoph Lameter, Dimitri Sivanich - provide timer interrupt
+ *             support via the posix timer interface
  */
 
 #include <linux/types.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/mmtimer.h>
 #include <linux/miscdevice.h>
+#include <linux/posix-timers.h>
+#include <linux/interrupt.h>
+
 #include <asm/uaccess.h>
 #include <asm/sn/addrs.h>
-#include <asm/sn/clksupport.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/shub_mmr.h>
+#include <asm/sn/nodepda.h>
+
+/* This is ugly and jbarnes has promised me to fix this later */
+#include "../../arch/ia64/sn/include/shubio.h"
 
 MODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>");
-MODULE_DESCRIPTION("Multimedia timer support");
+MODULE_DESCRIPTION("SGI Altix RTC Timer");
 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 MMTIMER_DESC "SGI Altix RTC Timer"
+#define MMTIMER_VERSION "2.0"
 
 #define RTC_BITS 55 /* 55 bits for this implementation */
 
+extern unsigned long sn_rtc_cycles_per_second;
+
+#define RTC_COUNTER_ADDR        ((long *)LOCAL_MMR_ADDR(SH_RTC))
+
+#define rtc_time()              (*RTC_COUNTER_ADDR)
+
 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);
@@ -55,6 +72,180 @@ static struct file_operations mmtimer_fops = {
        .ioctl =        mmtimer_ioctl,
 };
 
+/*
+ * Comparators and their associated info.  Shub has
+ * three comparison registers.
+ */
+
+/*
+ * We only have comparison registers RTC1-4 currently available per
+ * node.  RTC0 is used by SAL.
+ */
+#define NUM_COMPARATORS 3
+/* Check for an RTC interrupt pending */
+static int inline mmtimer_int_pending(int comparator)
+{
+       if (HUB_L((unsigned long *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)) &
+                       SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator)
+               return 1;
+       else
+               return 0;
+}
+/* Clear the RTC interrupt pending bit */
+static void inline mmtimer_clr_int_pending(int comparator)
+{
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS),
+               SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator);
+}
+
+/* Setup timer on comparator RTC1 */
+static void inline mmtimer_setup_int_0(u64 expires)
+{
+       u64 val;
+
+       /* Disable interrupt */
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE), 0UL);
+
+       /* Initialize comparator value */
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPB), -1L);
+
+       /* Clear pending bit */
+       mmtimer_clr_int_pending(0);
+
+       val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC1_INT_CONFIG_IDX_SHFT) |
+               ((u64)cpu_physical_id(smp_processor_id()) <<
+                       SH_RTC1_INT_CONFIG_PID_SHFT);
+
+       /* Set configuration */
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_CONFIG), val);
+
+       /* Enable RTC interrupts */
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE), 1UL);
+
+       /* Initialize comparator value */
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPB), expires);
+
+
+}
+
+/* Setup timer on comparator RTC2 */
+static void inline mmtimer_setup_int_1(u64 expires)
+{
+       u64 val;
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE), 0UL);
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPC), -1L);
+
+       mmtimer_clr_int_pending(1);
+
+       val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC2_INT_CONFIG_IDX_SHFT) |
+               ((u64)cpu_physical_id(smp_processor_id()) <<
+                       SH_RTC2_INT_CONFIG_PID_SHFT);
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_CONFIG), val);
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE), 1UL);
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPC), expires);
+}
+
+/* Setup timer on comparator RTC3 */
+static void inline mmtimer_setup_int_2(u64 expires)
+{
+       u64 val;
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE), 0UL);
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPD), -1L);
+
+       mmtimer_clr_int_pending(2);
+
+       val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC3_INT_CONFIG_IDX_SHFT) |
+               ((u64)cpu_physical_id(smp_processor_id()) <<
+                       SH_RTC3_INT_CONFIG_PID_SHFT);
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_CONFIG), val);
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE), 1UL);
+
+       HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPD), expires);
+}
+
+/*
+ * This function must be called with interrupts disabled and preemption off
+ * in order to insure that the setup succeeds in a deterministic time frame.
+ * It will check if the interrupt setup succeeded.
+ * mmtimer_setup will return the cycles that we were too late if the
+ * initialization failed.
+ */
+static int inline mmtimer_setup(int comparator, unsigned long expires)
+{
+
+       long diff;
+
+       switch (comparator) {
+       case 0:
+               mmtimer_setup_int_0(expires);
+               break;
+       case 1:
+               mmtimer_setup_int_1(expires);
+               break;
+       case 2:
+               mmtimer_setup_int_2(expires);
+               break;
+       }
+       /* We might've missed our expiration time */
+        diff = rtc_time() - expires;
+       if (diff > 0) {
+               if (mmtimer_int_pending(comparator)) {
+                       /* We'll get an interrupt for this once we're done */
+                        return 0;
+               }
+               /* Looks like we missed it */
+               return diff;
+        }
+
+       return 0;
+}
+
+static int inline mmtimer_disable_int(long nasid, int comparator)
+{
+       switch (comparator) {
+       case 0:
+               nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE),
+                       0UL) : REMOTE_HUB_S(nasid, SH_RTC1_INT_ENABLE, 0UL);
+               break;
+       case 1:
+               nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE),
+                       0UL) : REMOTE_HUB_S(nasid, SH_RTC2_INT_ENABLE, 0UL);
+               break;
+       case 2:
+               nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE),
+                       0UL) : REMOTE_HUB_S(nasid, SH_RTC3_INT_ENABLE, 0UL);
+               break;
+       default:
+               return -EFAULT;
+       }
+       return 0;
+}
+
+#define TIMER_OFF 0xbadcabLL
+
+/* There is one of these for each comparator */
+typedef struct mmtimer {
+       spinlock_t lock ____cacheline_aligned;
+       struct k_itimer *timer;
+       int i;
+       int cpu;
+       struct tasklet_struct tasklet;
+} mmtimer_t;
+
+/*
+ * Total number of comparators is comparators/node * MAX nodes/running kernel
+ */
+static mmtimer_t timers[NUM_COMPARATORS*MAX_COMPACT_NODES];
+
 /**
  * mmtimer_ioctl - ioctl interface for /dev/mmtimer
  * @inode: inode of the device
@@ -100,13 +291,13 @@ static int mmtimer_ioctl(struct inode *inode, struct file *file,
                break;
 
        case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */
-               if(copy_to_user((unsigned long *)arg, &mmtimer_femtoperiod,
-                               sizeof(unsigned long)))
+               if(copy_to_user((unsigned long __user *)arg,
+                               &mmtimer_femtoperiod, sizeof(unsigned long)))
                        return -EFAULT;
                break;
 
        case MMTIMER_GETFREQ: /* frequency in Hz */
-               if(copy_to_user((unsigned long *)arg,
+               if(copy_to_user((unsigned long __user *)arg,
                                &sn_rtc_cycles_per_second,
                                sizeof(unsigned long)))
                        return -EFAULT;
@@ -122,8 +313,8 @@ static int mmtimer_ioctl(struct inode *inode, struct file *file,
                break;
 
        case MMTIMER_GETCOUNTER:
-               if(copy_to_user((unsigned long *)arg, RTC_COUNTER_ADDR,
-                               sizeof(unsigned long)))
+               if(copy_to_user((unsigned long __user *)arg,
+                               RTC_COUNTER_ADDR, sizeof(unsigned long)))
                        return -EFAULT;
                break;
        default:
@@ -139,7 +330,7 @@ static int mmtimer_ioctl(struct inode *inode, struct file *file,
  * @file: file structure for the device
  * @vma: VMA to map the registers into
  *
- * Calls remap_page_range() to map the clock's registers into
+ * Calls remap_pfn_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)
@@ -162,9 +353,9 @@ static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
        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");
+       if (remap_pfn_range(vma, vma->vm_start, mmtimer_addr >> PAGE_SHIFT,
+                                       PAGE_SIZE, vma->vm_page_prot)) {
+               printk(KERN_ERR "remap_pfn_range failed in mmtimer.c\n");
                return -EAGAIN;
        }
 
@@ -177,6 +368,313 @@ static struct miscdevice mmtimer_miscdev = {
        &mmtimer_fops
 };
 
+static struct timespec sgi_clock_offset;
+static int sgi_clock_period;
+
+/*
+ * Posix Timer Interface
+ */
+
+static struct timespec sgi_clock_offset;
+static int sgi_clock_period;
+
+static int sgi_clock_get(struct timespec *tp)
+{
+       u64 nsec;
+
+       nsec = rtc_time() * sgi_clock_period
+                       + sgi_clock_offset.tv_nsec;
+       tp->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tp->tv_nsec)
+                       + sgi_clock_offset.tv_sec;
+       return 0;
+};
+
+static int sgi_clock_set(struct timespec *tp)
+{
+
+       u64 nsec;
+       u64 rem;
+
+       nsec = rtc_time() * sgi_clock_period;
+
+       sgi_clock_offset.tv_sec = tp->tv_sec - div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+
+       if (rem <= tp->tv_nsec)
+               sgi_clock_offset.tv_nsec = tp->tv_sec - rem;
+       else {
+               sgi_clock_offset.tv_nsec = tp->tv_sec + NSEC_PER_SEC - rem;
+               sgi_clock_offset.tv_sec--;
+       }
+       return 0;
+}
+
+/*
+ * Schedule the next periodic interrupt. This function will attempt
+ * to schedule a periodic interrupt later if necessary. If the scheduling
+ * of an interrupt fails then the time to skip is lengthened
+ * exponentially in order to ensure that the next interrupt
+ * can be properly scheduled..
+ */
+static int inline reschedule_periodic_timer(mmtimer_t *x)
+{
+       int n;
+       struct k_itimer *t = x->timer;
+
+       t->it_timer.magic = x->i;
+       t->it_overrun--;
+
+       n = 0;
+       do {
+
+               t->it_timer.expires += t->it_incr << n;
+               t->it_overrun += 1 << n;
+               n++;
+               if (n > 20)
+                       return 1;
+
+       } while (mmtimer_setup(x->i, t->it_timer.expires));
+
+       return 0;
+}
+
+/**
+ * mmtimer_interrupt - timer interrupt handler
+ * @irq: irq received
+ * @dev_id: device the irq came from
+ * @regs: register state upon receipt of the interrupt
+ *
+ * Called when one of the comarators matches the counter, This
+ * routine will send signals to processes that have requested
+ * them.
+ *
+ * This interrupt is run in an interrupt context
+ * by the SHUB. It is therefore safe to locally access SHub
+ * registers.
+ */
+static irqreturn_t
+mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int i;
+       mmtimer_t *base = timers + cpuid_to_cnodeid(smp_processor_id()) *
+                                               NUM_COMPARATORS;
+       unsigned long expires = 0;
+       int result = IRQ_NONE;
+
+       /*
+        * Do this once for each comparison register
+        */
+       for (i = 0; i < NUM_COMPARATORS; i++) {
+               /* Make sure this doesn't get reused before tasklet_sched */
+               spin_lock(&base[i].lock);
+               if (base[i].cpu == smp_processor_id()) {
+                       if (base[i].timer)
+                               expires = base[i].timer->it_timer.expires;
+                       /* expires test won't work with shared irqs */
+                       if ((mmtimer_int_pending(i) > 0) ||
+                               (expires && (expires < rtc_time()))) {
+                               mmtimer_clr_int_pending(i);
+                               tasklet_schedule(&base[i].tasklet);
+                               result = IRQ_HANDLED;
+                       }
+               }
+               spin_unlock(&base[i].lock);
+               expires = 0;
+       }
+       return result;
+}
+
+void mmtimer_tasklet(unsigned long data) {
+       mmtimer_t *x = (mmtimer_t *)data;
+       struct k_itimer *t = x->timer;
+       unsigned long flags;
+
+       if (t == NULL)
+               return;
+
+       /* Send signal and deal with periodic signals */
+       spin_lock_irqsave(&t->it_lock, flags);
+       spin_lock(&x->lock);
+       /* If timer was deleted between interrupt and here, leave */
+       if (t != x->timer)
+               goto out;
+       t->it_overrun = 0;
+
+       if (tasklist_lock.write_lock || posix_timer_event(t, 0) != 0) {
+
+               // printk(KERN_WARNING "mmtimer: cannot deliver signal.\n");
+
+               t->it_overrun++;
+       }
+       if(t->it_incr) {
+               /* Periodic timer */
+               if (reschedule_periodic_timer(x)) {
+                       printk(KERN_WARNING "mmtimer: unable to reschedule\n");
+                       x->timer = NULL;
+               }
+       } else {
+               /* Ensure we don't false trigger in mmtimer_interrupt */
+               t->it_timer.expires = 0;
+       }
+       t->it_overrun_last = t->it_overrun;
+out:
+       spin_unlock(&x->lock);
+       spin_unlock_irqrestore(&t->it_lock, flags);
+}
+
+static int sgi_timer_create(struct k_itimer *timer)
+{
+       /* Insure that a newly created timer is off */
+       timer->it_timer.magic = TIMER_OFF;
+       return 0;
+}
+
+/* This does not really delete a timer. It just insures
+ * that the timer is not active
+ *
+ * Assumption: it_lock is already held with irq's disabled
+ */
+static int sgi_timer_del(struct k_itimer *timr)
+{
+       int i = timr->it_timer.magic;
+       cnodeid_t nodeid = timr->it_timer.data;
+       mmtimer_t *t = timers + nodeid * NUM_COMPARATORS +i;
+       unsigned long irqflags;
+
+       if (i != TIMER_OFF) {
+               spin_lock_irqsave(&t->lock, irqflags);
+               mmtimer_disable_int(cnodeid_to_nasid(nodeid),i);
+               t->timer = NULL;
+               timr->it_timer.magic = TIMER_OFF;
+               timr->it_timer.expires = 0;
+               spin_unlock_irqrestore(&t->lock, irqflags);
+       }
+       return 0;
+}
+
+#define timespec_to_ns(x) ((x).tv_nsec + (x).tv_sec * NSEC_PER_SEC)
+#define ns_to_timespec(ts, nsec) (ts).tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &(ts).tv_nsec)
+
+/* Assumption: it_lock is already held with irq's disabled */
+static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
+{
+
+       if (timr->it_timer.magic == TIMER_OFF) {
+               cur_setting->it_interval.tv_nsec = 0;
+               cur_setting->it_interval.tv_sec = 0;
+               cur_setting->it_value.tv_nsec = 0;
+               cur_setting->it_value.tv_sec =0;
+               return;
+       }
+
+       ns_to_timespec(cur_setting->it_interval, timr->it_incr * sgi_clock_period);
+       ns_to_timespec(cur_setting->it_value, (timr->it_timer.expires - rtc_time())* sgi_clock_period);
+       return;
+}
+
+
+static int sgi_timer_set(struct k_itimer *timr, int flags,
+       struct itimerspec * new_setting,
+       struct itimerspec * old_setting)
+{
+
+       int i;
+       unsigned long when, period, irqflags;
+       int err = 0;
+       cnodeid_t nodeid;
+       mmtimer_t *base;
+
+       if (old_setting)
+               sgi_timer_get(timr, old_setting);
+
+       sgi_timer_del(timr);
+       when = timespec_to_ns(new_setting->it_value);
+       period = timespec_to_ns(new_setting->it_interval);
+
+       if (when == 0)
+               /* Clear timer */
+               return 0;
+
+       if (flags & TIMER_ABSTIME) {
+               struct timespec n;
+
+               getnstimeofday(&n);
+               when -= timespec_to_ns(n);
+       }
+
+       /*
+        * Convert to sgi clock period. Need to keep rtc_time() as near as possible
+        * to getnstimeofday() in order to be as faithful as possible to the time
+        * specified.
+        */
+       when = (when + sgi_clock_period - 1) / sgi_clock_period + rtc_time();
+       period = (period + sgi_clock_period - 1)  / sgi_clock_period;
+
+       /*
+        * We are allocating a local SHub comparator. If we would be moved to another
+        * cpu then another SHub may be local to us. Prohibit that by switching off
+        * preemption.
+        */
+       preempt_disable();
+
+       nodeid =  cpuid_to_cnodeid(smp_processor_id());
+       base = timers + nodeid * NUM_COMPARATORS;
+retry:
+       /* Don't use an allocated timer, or a deleted one that's pending */
+       for(i = 0; i< NUM_COMPARATORS; i++) {
+               if (!base[i].timer && !base[i].tasklet.state) {
+                       break;
+               }
+       }
+
+       if (i == NUM_COMPARATORS) {
+               preempt_enable();
+               return -EBUSY;
+       }
+
+       spin_lock_irqsave(&base[i].lock, irqflags);
+
+       if (base[i].timer || base[i].tasklet.state != 0) {
+               spin_unlock_irqrestore(&base[i].lock, irqflags);
+               goto retry;
+       }
+       base[i].timer = timr;
+       base[i].cpu = smp_processor_id();
+
+       timr->it_timer.magic = i;
+       timr->it_timer.data = nodeid;
+       timr->it_incr = period;
+       timr->it_timer.expires = when;
+
+       if (period == 0) {
+               if (mmtimer_setup(i, when)) {
+                       mmtimer_disable_int(-1, i);
+                       posix_timer_event(timr, 0);
+                       timr->it_timer.expires = 0;
+               }
+       } else {
+               timr->it_timer.expires -= period;
+               if (reschedule_periodic_timer(base+i))
+                       err = -EINVAL;
+       }
+
+       spin_unlock_irqrestore(&base[i].lock, irqflags);
+
+       preempt_enable();
+
+       return err;
+}
+
+static struct k_clock sgi_clock = {
+       .res = 0,
+       .clock_set = sgi_clock_set,
+       .clock_get = sgi_clock_get,
+       .timer_create = sgi_timer_create,
+       .nsleep = do_posix_clock_nonanosleep,
+       .timer_set = sgi_timer_set,
+       .timer_del = sgi_timer_del,
+       .timer_get = sgi_timer_get
+};
+
 /**
  * mmtimer_init - device initialization routine
  *
@@ -184,6 +682,8 @@ static struct miscdevice mmtimer_miscdev = {
  */
 static int __init mmtimer_init(void)
 {
+       unsigned i;
+
        if (!ia64_platform_is("sn2"))
                return -1;
 
@@ -199,6 +699,20 @@ static int __init mmtimer_init(void)
        mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second /
                               2) / sn_rtc_cycles_per_second;
 
+       for (i=0; i< NUM_COMPARATORS*MAX_COMPACT_NODES; i++) {
+               spin_lock_init(&timers[i].lock);
+               timers[i].timer = NULL;
+               timers[i].cpu = 0;
+               timers[i].i = i % NUM_COMPARATORS;
+               tasklet_init(&timers[i].tasklet, mmtimer_tasklet, (unsigned long) (timers+i));
+       }
+
+       if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, SA_PERCPU_IRQ, MMTIMER_NAME, NULL)) {
+               printk(KERN_WARNING "%s: unable to allocate interrupt.",
+                       MMTIMER_NAME);
+               return -1;
+       }
+
        strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME);
        if (misc_register(&mmtimer_miscdev)) {
                printk(KERN_ERR "%s: failed to register device\n",
@@ -206,6 +720,9 @@ static int __init mmtimer_init(void)
                return -1;
        }
 
+       sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second;
+       register_posix_clock(CLOCK_SGI_CYCLE, &sgi_clock);
+
        printk(KERN_INFO "%s: v%s, %ld MHz\n", MMTIMER_DESC, MMTIMER_VERSION,
               sn_rtc_cycles_per_second/(unsigned long)1E6);
 
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
index f344ed3..62c67cd 100644 (file)
@@ -696,7 +696,7 @@ static void __exit nwflash_exit(void)
 
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(flashdebug, "i");
+module_param(flashdebug, bool, 0644);
 
 module_init(nwflash_init);
 module_exit(nwflash_exit);
index 061237b..b20a941 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/tty_driver.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #ifndef MODULE
 #include <linux/ctype.h> /* We only need it for parsing the "digi="-line */
@@ -73,7 +74,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 #include <asm/semaphore.h>
 
 #define VERSION        "1.6.3"
@@ -112,13 +112,13 @@ static int numports[]     = {0, 0, 0, 0};
 MODULE_AUTHOR("Bernhard Kaindl");
 MODULE_DESCRIPTION("Digiboard PC/X{i,e,eve} driver");
 MODULE_LICENSE("GPL");
-MODULE_PARM(verbose,     "i");
-MODULE_PARM(debug,       "i");
-MODULE_PARM(io,          "1-4i");
-MODULE_PARM(membase,     "1-4i");
-MODULE_PARM(memsize,     "1-4i");
-MODULE_PARM(altpin,      "1-4i");
-MODULE_PARM(numports,    "1-4i");
+module_param(verbose,     bool, 0644);
+module_param(debug,       bool, 0644);
+module_param_array(io,          int, NULL, 0);
+module_param_array(membase,     int, NULL, 0);
+module_param_array(memsize,     int, NULL, 0);
+module_param_array(altpin,      int, NULL, 0);
+module_param_array(numports,    int, NULL, 0);
 
 #endif /* MODULE */
 
@@ -148,7 +148,7 @@ static void pcxx_error(int, char *);
 static void pcxe_close(struct tty_struct *, struct file *);
 static int pcxe_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
 static void pcxe_set_termios(struct tty_struct *, struct termios *);
-static int pcxe_write(struct tty_struct *, int, const unsigned char *, int);
+static int pcxe_write(struct tty_struct *, const unsigned char *, int);
 static int pcxe_write_room(struct tty_struct *);
 static int pcxe_chars_in_buffer(struct tty_struct *);
 static void pcxe_flush_buffer(struct tty_struct *);
@@ -538,8 +538,7 @@ static void pcxe_close(struct tty_struct * tty, struct file * filp)
                info->tty = NULL;
                if(info->blocked_open) {
                        if(info->close_delay) {
-                               current->state = TASK_INTERRUPTIBLE;
-                               schedule_timeout(info->close_delay);
+                               msleep_interruptible(jiffies_to_msecs(info->close_delay));
                        }
                        wake_up_interruptible(&info->open_wait);
                }
@@ -571,7 +570,7 @@ void pcxe_hangup(struct tty_struct *tty)
 
 
 
-static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+static int pcxe_write(struct tty_struct * tty, const unsigned char *buf, int count)
 {
        struct channel *ch;
        volatile struct board_chan *bc;
@@ -586,33 +585,6 @@ static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned cha
        bc = ch->brdchan;
        size = ch->txbufsize;
 
-       if (from_user) {
-
-               down(&ch->tmp_buf_sem);
-               save_flags(flags);
-               cli();
-               globalwinon(ch);
-               head = bc->tin & (size - 1);
-               /* It seems to be necessary to make sure that the value is stable here somehow
-                  This is a rather odd pice of code here. */
-               do
-               {
-                       tail = bc->tout;
-               } while (tail != bc->tout);
-               
-               tail &= (size - 1);
-               stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
-               count = min(stlen, count);
-               memoff(ch);
-               restore_flags(flags);
-
-               if (count)
-                       if (copy_from_user(ch->tmp_buf, buf, count))
-                               count = 0;
-
-               buf = ch->tmp_buf;
-       }
-
        /*
         * All data is now local
         */
@@ -659,16 +631,13 @@ static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned cha
        memoff(ch);
        restore_flags(flags);
        
-       if(from_user)
-               up(&ch->tmp_buf_sem);
-
        return(total);
 }
 
 
 static void pcxe_put_char(struct tty_struct *tty, unsigned char c)
 {
-       pcxe_write(tty, 0, &c, 1);
+       pcxe_write(tty, &c, 1);
        return;
 }
 
index 4698af2..e0bb00f 100644 (file)
@@ -79,7 +79,7 @@
 #include <linux/pc_keyb.h>
 
 #include <asm/keyboard.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 #include <asm/system.h>
index 0cc0237..aa23b1c 100644 (file)
@@ -236,9 +236,9 @@ long rio_irqmask = -1;
 MODULE_AUTHOR("Rogier Wolff <R.E.Wolff@bitwizard.nl>, Patrick van de Lageweg <patrick@bitwizard.nl>");
 MODULE_DESCRIPTION("RIO driver");
 MODULE_LICENSE("GPL");
-MODULE_PARM(rio_poll, "i");
-MODULE_PARM(rio_debug, "i");
-MODULE_PARM(rio_irqmask, "i");
+module_param(rio_poll, int, 0);
+module_param(rio_debug, int, 0644);
+module_param(rio_irqmask, long, 0);
 
 static struct real_driver rio_real_driver = {
   rio_disable_tx_interrupts,
@@ -330,8 +330,7 @@ int RIODelay (struct Port *PortP, int njiffies)
   func_enter ();
 
   rio_dprintk (RIO_DEBUG_DELAY, "delaying %d jiffies\n", njiffies);  
-  current->state = TASK_INTERRUPTIBLE;
-  schedule_timeout(njiffies);
+  msleep_interruptible(jiffies_to_msecs(njiffies));
   func_exit();
 
   if (signal_pending(current))
@@ -347,8 +346,7 @@ int RIODelay_ni (struct Port *PortP, int njiffies)
   func_enter ();
 
   rio_dprintk (RIO_DEBUG_DELAY, "delaying %d jiffies (ni)\n", njiffies);  
-  current->state = TASK_UNINTERRUPTIBLE;
-  schedule_timeout(njiffies);
+  msleep(jiffies_to_msecs(njiffies));
   func_exit();
   return !RIO_FAIL;
 }
index a35ea03..55a3a01 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/fcntl.h>
 #include <linux/major.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 
@@ -1114,8 +1115,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
                 */
                timeout = jiffies+HZ;
                while(port->IER & IER_TXEMPTY)  {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(port->timeout);
+                       msleep_interruptible(jiffies_to_msecs(port->timeout));
                        if (time_after(jiffies, timeout))
                                break;
                }
@@ -1130,8 +1130,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
        port->tty = NULL;
        if (port->blocked_open) {
                if (port->close_delay) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(port->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(port->close_delay));
                }
                wake_up_interruptible(&port->open_wait);
        }
@@ -1140,7 +1139,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
 out:   restore_flags(flags);
 }
 
-static int rc_write(struct tty_struct * tty, int from_user, 
+static int rc_write(struct tty_struct * tty, 
                    const unsigned char *buf, int count)
 {
        struct riscom_port *port = (struct riscom_port *)tty->driver_data;
@@ -1157,54 +1156,23 @@ static int rc_write(struct tty_struct * tty, int from_user,
                return 0;
 
        save_flags(flags);
-       if (from_user) {
-               down(&tmp_buf_sem);
-               while (1) {
-                       cli();          
-                       c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                                 SERIAL_XMIT_SIZE - port->xmit_head));
-                       if (c <= 0)
-                               break;
-
-                       c -= copy_from_user(tmp_buf, buf, c);
-                       if (!c) {
-                               if (!total)
-                                       total = -EFAULT;
-                               break;
-                       }
-
-                       cli();
-                       c = min_t(int, c, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                        SERIAL_XMIT_SIZE - port->xmit_head));
-                       memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
-                       port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-                       port->xmit_cnt += c;
+       while (1) {
+               cli();          
+               c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+                                         SERIAL_XMIT_SIZE - port->xmit_head));
+               if (c <= 0) {
                        restore_flags(flags);
-
-                       buf += c;
-                       count -= c;
-                       total += c;
+                       break;
                }
-               up(&tmp_buf_sem);
-       } else {
-               while (1) {
-                       cli();          
-                       c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                                 SERIAL_XMIT_SIZE - port->xmit_head));
-                       if (c <= 0) {
-                               restore_flags(flags);
-                               break;
-                       }
 
-                       memcpy(port->xmit_buf + port->xmit_head, buf, c);
-                       port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-                       port->xmit_cnt += c;
-                       restore_flags(flags);
+               memcpy(port->xmit_buf + port->xmit_head, buf, c);
+               port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+               port->xmit_cnt += c;
+               restore_flags(flags);
 
-                       buf += c;
-                       count -= c;
-                       total += c;
-               }
+               buf += c;
+               count -= c;
+               total += c;
        }
 
        cli();
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");
index 885621e..c2deac9 100644 (file)
@@ -39,6 +39,9 @@
  * - don't use the panic function in serial167_init
  * - do resource release on failure on serial167_init
  * - include missing restore_flags in mvme167_serial_console_setup
+ *
+ * Kars de Jong <jongk@linux-m68k.org> - 2004/09/06
+ * - replace bottom half handler with task queue handler
  */
 
 #include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/console.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/bitops.h>
 #include <asm/mvme16xhw.h>
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -89,8 +92,6 @@
 
 #define SERIAL_TYPE_NORMAL  1
 
-DECLARE_TASK_QUEUE(tq_cyclades);
-
 static struct tty_driver *cy_serial_driver;
 extern int serial_console;
 static struct cyclades_port *serial_console_info = NULL;
@@ -373,8 +374,7 @@ static inline void
 cy_sched_event(struct cyclades_port *info, int event)
 {
     info->event |= 1 << event; /* remember what kind of event and who */
-    queue_task(&info->tqueue, &tq_cyclades); /* it belongs to */
-    mark_bh(CYCLADES_BH);                       /* then trigger event */
+    schedule_work(&info->tqueue);
 } /* cy_sched_event */
 
 
@@ -467,7 +467,7 @@ cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp)
               and nothing could be done about it!!! */
        }
     }
-    queue_task(&tty->flip.tqueue, &tq_timer);
+    schedule_delayed_work(&tty->flip.work, 1);
     /* end of service */
     base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
     return IRQ_HANDLED;
@@ -702,7 +702,7 @@ cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
            udelay(10L);
 #endif
         }
-       queue_task(&tty->flip.tqueue, &tq_timer);
+       schedule_delayed_work(&tty->flip.work, 1);
     }
     /* end of service */
     base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
@@ -713,7 +713,7 @@ cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
  * 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
- * cy_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * cy#/_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 cy_sched_event(), and they get done here.
@@ -721,9 +721,7 @@ cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
  * This is done through one level of indirection--the task queue.
  * When a hardware interrupt service routine wants service by the
  * driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the tq_cyclades work queue and sets a request flag
- * via mark_bh for processing that queue.  When the time is right,
- * do_cyclades_bh is called (because of the mark_bh) and it requests
+ * per port) to the keventd work queue and sets a request flag
  * that the work queue be processed.
  *
  * Although this may seem unwieldy, it gives the system a way to
@@ -731,12 +729,6 @@ cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
  * structure) to the bottom half of the driver.  Previous kernels
  * had to poll every port to see if that port needed servicing.
  */
-static void
-do_cyclades_bh(void)
-{
-    run_task_queue(&tq_cyclades);
-} /* do_cyclades_bh */
-
 static void
 do_softint(void *private_)
 {
@@ -1208,7 +1200,7 @@ cy_flush_chars(struct tty_struct *tty)
     port is already active, there is no need to kick it.
  */
 static int
-cy_write(struct tty_struct * tty, int from_user,
+cy_write(struct tty_struct * tty,
            const unsigned char *buf, int count)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
@@ -1227,53 +1219,23 @@ cy_write(struct tty_struct * tty, int from_user,
         return 0;
     }
 
-    if (from_user) {
-           down(&tmp_buf_sem);
-           while (1) {
-                   c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                             SERIAL_XMIT_SIZE - info->xmit_head));
-                   if (c <= 0)
-                           break;
-
-                   c -= copy_from_user(tmp_buf, buf, c);
-                   if (!c) {
-                           if (!total)
-                                   total = -EFAULT;
-                           break;
-                   }
-
-                   local_irq_save(flags);
-                   c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                         SERIAL_XMIT_SIZE - info->xmit_head));
-                   memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-                   info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-                   info->xmit_cnt += c;
+    while (1) {
+           local_irq_save(flags);
+           c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                     SERIAL_XMIT_SIZE - info->xmit_head));
+           if (c <= 0) {
                    local_irq_restore(flags);
-
-                   buf += c;
-                   count -= c;
-                   total += c;
+                   break;
            }
-           up(&tmp_buf_sem);
-    } else {
-           while (1) {
-                   local_irq_save(flags);
-                   c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                             SERIAL_XMIT_SIZE - info->xmit_head));
-                   if (c <= 0) {
-                           local_irq_restore(flags);
-                           break;
-                   }
 
-                   memcpy(info->xmit_buf + info->xmit_head, buf, c);
-                   info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-                   info->xmit_cnt += c;
-                   local_irq_restore(flags);
+           memcpy(info->xmit_buf + info->xmit_head, buf, c);
+           info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+           info->xmit_cnt += c;
+           local_irq_restore(flags);
 
-                   buf += c;
-                   count -= c;
-                   total += c;
-           }
+           buf += c;
+           count -= c;
+           total += c;
     }
 
     if (info->xmit_cnt
@@ -1840,8 +1802,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
     info->tty = 0;
     if (info->blocked_open) {
        if (info->close_delay) {
-           current->state = TASK_INTERRUPTIBLE;
-           schedule_timeout(info->close_delay);
+           msleep_interruptible(jiffies_to_msecs(info->close_delay));
        }
        wake_up_interruptible(&info->open_wait);
     }
@@ -2309,8 +2270,6 @@ scrn[1] = '\0';
            return ret;
     }
 
-    init_bh(CYCLADES_BH, do_cyclades_bh);
-
     port_num = 0;
     info = cy_port;
     for (index = 0; index < 1; index++) {
@@ -2348,8 +2307,7 @@ scrn[1] = '\0';
                info->blocked_open = 0;
                info->default_threshold = 0;
                info->default_timeout = 0;
-               info->tqueue.routine = do_softint;
-               info->tqueue.data = info;
+               INIT_WORK(&info->tqueue, do_softint, info);
                init_waitqueue_head(&info->open_wait);
                init_waitqueue_head(&info->close_wait);
                /* info->session */
index 25917e0..9d027ec 100644 (file)
 #include <linux/poll.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <asm/sn/io.h>
 #include <asm/sn/sn_sal.h>
+#include <asm/sn/module.h>
+#include <asm/sn/geo.h>
 #include <asm/sn/nodepda.h>
 #include "snsc.h"
 
@@ -364,17 +367,15 @@ int __init
 scdrv_init(void)
 {
        geoid_t geoid;
-       cmoduleid_t cmod;
-       int i;
+       cnodeid_t cnode;
        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),
+       if (alloc_chrdev_region(&first_dev, 0, numionodes,
                                SYSCTL_BASENAME) < 0) {
                printk("%s: failed to register SN system controller device\n",
                       __FUNCTION__);
@@ -382,16 +383,8 @@ scdrv_init(void)
        }
        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];
+       for (cnode = 0; cnode < numionodes; cnode++) {
+                       geoid = cnodeid_get_geoid(cnode);
                        devnamep = devname;
                        format_module_id(devnamep, geo_module(geoid),
                                         MODULE_FORMAT_BRIEF);
@@ -410,7 +403,7 @@ scdrv_init(void)
                        memset(scd, 0, sizeof (struct sysctl_data_s));
 
                        /* initialize sysctl device data fields */
-                       scd->scd_nasid = cnodeid_to_nasid(m->nodes[i]);
+                       scd->scd_nasid = cnodeid_to_nasid(cnode);
                        if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) {
                                printk("%s: failed to allocate driver buffer"
                                       "(%s%s)\n", __FUNCTION__,
@@ -431,7 +424,7 @@ scdrv_init(void)
                                continue;
                        }
 
-                       dev = first_dev + m->nodes[i];
+                       dev = first_dev + cnode;
                        cdev_init(&scd->scd_cdev, &scdrv_fops);
                        if (cdev_add(&scd->scd_cdev, dev, 1)) {
                                printk("%s: failed to register system"
@@ -448,7 +441,6 @@ scdrv_init(void)
                        ia64_sn_irtr_intr_enable(scd->scd_nasid,
                                                 0 /*ignored */ ,
                                                 SAL_IROUTER_INTR_RECV);
-               }
        }
        return 0;
 }
index bf82f06..5a33227 100644 (file)
@@ -1452,8 +1452,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
                 */
                timeout = jiffies+HZ;
                while(port->IER & IER_TXEMPTY) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(port->timeout);
+                       msleep_interruptible(jiffies_to_msecs(port->timeout));
                        if (time_after(jiffies, timeout)) {
                                printk (KERN_INFO "Timeout waiting for close\n");
                                break;
@@ -1470,8 +1469,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
        port->tty = NULL;
        if (port->blocked_open) {
                if (port->close_delay) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(port->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(port->close_delay));
                }
                wake_up_interruptible(&port->open_wait);
        }
@@ -1481,7 +1479,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
 }
 
 
-static int sx_write(struct tty_struct * tty, int from_user, 
+static int sx_write(struct tty_struct * tty, 
                     const unsigned char *buf, int count)
 {
        struct specialix_port *port = (struct specialix_port *)tty->driver_data;
@@ -1498,52 +1496,22 @@ static int sx_write(struct tty_struct * tty, int from_user,
                return 0;
 
        save_flags(flags);
-       if (from_user) {
-               down(&tmp_buf_sem);
-               while (1) {
-                       c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                          SERIAL_XMIT_SIZE - port->xmit_head));
-                       if (c <= 0)
-                               break;
-
-                       c -= copy_from_user(tmp_buf, buf, c);
-                       if (!c) {
-                               if (!total)
-                                       total = -EFAULT;
-                               break;
-                       }
-
-                       cli();
-                       c = min_t(int, c, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                      SERIAL_XMIT_SIZE - port->xmit_head));
-                       memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
-                       port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-                       port->xmit_cnt += c;
+       while (1) {
+               cli();
+               c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+                                  SERIAL_XMIT_SIZE - port->xmit_head));
+               if (c <= 0) {
                        restore_flags(flags);
-
-                       buf += c;
-                       count -= c;
-                       total += c;
+                       break;
                }
-               up(&tmp_buf_sem);
-       } else {
-               while (1) {
-                       cli();
-                       c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                          SERIAL_XMIT_SIZE - port->xmit_head));
-                       if (c <= 0) {
-                               restore_flags(flags);
-                               break;
-                       }
-                       memcpy(port->xmit_buf + port->xmit_head, buf, c);
-                       port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-                       port->xmit_cnt += c;
-                       restore_flags(flags);
+               memcpy(port->xmit_buf + port->xmit_head, buf, c);
+               port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+               port->xmit_cnt += c;
+               restore_flags(flags);
 
-                       buf += c;
-                       count -= c;
-                       total += c;
-               }
+               buf += c;
+               count -= c;
+               total += c;
        }
 
        cli();
@@ -2218,8 +2186,8 @@ int iobase[SX_NBOARD]  = {0,};
 
 int irq [SX_NBOARD] = {0,};
 
-MODULE_PARM(iobase,"1-" __MODULE_STRING(SX_NBOARD) "i");
-MODULE_PARM(irq,"1-" __MODULE_STRING(SX_NBOARD) "i");
+module_param_array(iobase, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
 
 /*
  * You can setup up to 4 boards.
index a990eb7..533d286 100644 (file)
@@ -460,9 +460,27 @@ static inline int sx_paranoia_check(struct sx_port const * port,
 
 
 #ifdef DEBUG
-static void my_hd (unsigned char *addr, int len)
+static void my_hd_io(void __iomem *p, int len)
 {
        int i, j, ch;
+       unsigned char __iomem *addr = p;
+
+       for (i=0;i<len;i+=16) {
+               printk ("%p ", addr+i);
+               for (j=0;j<16;j++) {
+                       printk ("%02x %s", readb(addr+j+i), (j==7)?" ":"");
+               }
+               for (j=0;j<16;j++) {
+                       ch = readb(addr+j+i);
+                       printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+               }
+               printk ("\n");
+       }
+}
+static void my_hd(void *p, int len)
+{
+       int i, j, ch;
+       unsigned char *addr = p;
 
        for (i=0;i<len;i+=16) {
                printk ("%p ", addr+i);
@@ -1452,11 +1470,10 @@ static int sx_open  (struct tty_struct * tty, struct file * filp)
 
 #if 0
        if (sx_debug & SX_DEBUG_OPEN)
-               my_hd ((unsigned char *)port, sizeof (*port));
+               my_hd (port, sizeof (*port));
 #else
        if (sx_debug & SX_DEBUG_OPEN)
-               my_hd ((unsigned char *)port->board->base + port->ch_base, 
-                      sizeof (*port));
+               my_hd_io (port->board->base + port->ch_base, sizeof (*port));
 #endif
 
        if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
@@ -1499,7 +1516,7 @@ static void sx_close (void *ptr)
        sx_send_command (port, HS_CLOSE, 0, 0);
 
        while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) {
-               current->state = TASK_INTERRUPTIBLE;
+               set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout (1);
                if (signal_pending (current))
                                break;
@@ -1675,7 +1692,7 @@ static int sx_fw_ioctl (struct inode *inode, struct file *filp,
                                        kfree (tmp);
                                        return -EFAULT;
                                }
-                               memcpy_toio    ((char *) (board->base2 + offset + i), tmp, 
+                               memcpy_toio(board->base2 + offset + i, tmp, 
                                                (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
                        }
 
@@ -1892,9 +1909,9 @@ static int sx_init_board (struct sx_board *board)
        /* Ok. So now the processor on the card is running. It gathered
           some info for us... */
        sx_dprintk (SX_DEBUG_INIT, "The sxcard structure:\n");
-       if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base), 0x10);
+       if (sx_debug & SX_DEBUG_INIT) my_hd_io (board->base, 0x10);
        sx_dprintk (SX_DEBUG_INIT, "the first sx_module structure:\n");
-       if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base + 0x80), 0x30);
+       if (sx_debug & SX_DEBUG_INIT) my_hd_io (board->base + 0x80, 0x30);
 
        sx_dprintk (SX_DEBUG_INIT, 
                    "init_status: %x, %dk memory, firmware V%x.%02x,\n", 
@@ -2047,18 +2064,18 @@ static int probe_sx (struct sx_board *board)
        func_enter();
 
        if (!IS_CF_BOARD (board)) {    
-               sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %lx.\n", 
+               sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %p.\n", 
                            board->base + SX_VPD_ROM);
 
                if (sx_debug & SX_DEBUG_PROBE)
-                       my_hd ((char *)(board->base + SX_VPD_ROM), 0x40);
+                       my_hd_io(board->base + SX_VPD_ROM, 0x40);
 
                p = (char *) &vpdp;
                for (i=0;i< sizeof (struct vpd_prom);i++)
                        *p++ = read_sx_byte (board, SX_VPD_ROM + i*2);
 
                if (sx_debug & SX_DEBUG_PROBE)
-                       my_hd ((char *)&vpdp, 0x20);
+                       my_hd (&vpdp, 0x20);
 
                sx_dprintk (SX_DEBUG_PROBE, "checking identifier...\n");
 
@@ -2088,8 +2105,8 @@ static int probe_sx (struct sx_board *board)
                }
 
                if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
-                       if (board->base & 0x8000) {
-                               printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->base);
+                       if (board->hw_base & 0x8000) {
+                               printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->hw_base);
                                printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
                        }
                }
@@ -2121,11 +2138,11 @@ static int probe_si (struct sx_board *board)
        int i;
 
        func_enter();
-       sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at %lx.\n", board->hw_base,
+       sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at %p.\n", board->hw_base,
                    board->base + SI2_ISA_ID_BASE);
 
        if (sx_debug & SX_DEBUG_PROBE)
-               my_hd ((char *)(board->base + SI2_ISA_ID_BASE), 0x8);
+               my_hd_io(board->base + SI2_ISA_ID_BASE, 0x8);
 
        if (!IS_EISA_BOARD(board)) {
          if( IS_SI1_BOARD(board) ) 
@@ -2359,7 +2376,7 @@ static void __exit sx_release_drivers(void)
 static void fix_sx_pci (struct pci_dev *pdev, struct sx_board *board)
 {
        unsigned int hwbase;
-       unsigned long rebase;
+       void __iomem *rebase;
        unsigned int t;
 
 #define CNTRL_REG_OFFSET        0x50
@@ -2367,13 +2384,13 @@ static void fix_sx_pci (struct pci_dev *pdev, struct sx_board *board)
 
        pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
        hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
-       rebase = (ulong) ioremap(hwbase, 0x80);
+       rebase = ioremap(hwbase, 0x80);
        t = readl (rebase + CNTRL_REG_OFFSET);
        if (t != CNTRL_REG_GOODVALUE) {
                printk (KERN_DEBUG "sx: performing cntrl reg fix: %08x -> %08x\n", t, CNTRL_REG_GOODVALUE); 
                writel (CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
        }
-       iounmap ((char *) rebase);
+       iounmap(rebase);
 }
 #endif
 
@@ -2441,7 +2458,7 @@ static int __init sx_init(void)
                else
                        board->hw_base = pci_resource_start (pdev, 2);
                board->base2 = 
-               board->base = (ulong) ioremap(board->hw_base, WINDOW_LEN (board));
+               board->base = ioremap(board->hw_base, WINDOW_LEN (board));
                if (!board->base) {
                        printk(KERN_ERR "ioremap failed\n");
                        /* XXX handle error */
@@ -2453,14 +2470,14 @@ static int __init sx_init(void)
 
                board->irq = pdev->irq;
 
-               sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%lx(%d) %x.\n", 
+               sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%p(%d) %x.\n", 
                            tint, boards[found].base, board->irq, board->flags);
 
                if (probe_sx (board)) {
                        found++;
                        fix_sx_pci (pdev, board);
                } else 
-                       iounmap ((char *) (board->base));
+                       iounmap(board->base);
        }
 #endif
 
@@ -2468,7 +2485,7 @@ static int __init sx_init(void)
                board = &boards[found];
                board->hw_base = sx_probe_addrs[i];
                board->base2 =
-               board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN);
+               board->base = ioremap(board->hw_base, SX_WINDOW_LEN);
                board->flags &= ~SX_BOARD_TYPE;
                board->flags |= SX_ISA_BOARD;
                board->irq = sx_irqmask?-1:0;
@@ -2476,7 +2493,7 @@ static int __init sx_init(void)
                if (probe_sx (board)) {
                        found++;
                } else {
-                       iounmap ((char *) (board->base));
+                       iounmap(board->base);
                }
        }
 
@@ -2484,7 +2501,7 @@ static int __init sx_init(void)
                board = &boards[found];
                board->hw_base = si_probe_addrs[i];
                board->base2 =
-               board->base = (ulong) ioremap(board->hw_base, SI2_ISA_WINDOW_LEN);
+               board->base = ioremap(board->hw_base, SI2_ISA_WINDOW_LEN);
                board->flags &= ~SX_BOARD_TYPE;
                board->flags |=  SI_ISA_BOARD;
                board->irq = sx_irqmask ?-1:0;
@@ -2492,14 +2509,14 @@ static int __init sx_init(void)
                if (probe_si (board)) {
                        found++;
                } else {
-                       iounmap ((char *) (board->base));
+                       iounmap (board->base);
                }
        }
        for (i=0;i<NR_SI1_ADDRS;i++) {
                board = &boards[found];
                board->hw_base = si1_probe_addrs[i];
                board->base2 =
-               board->base = (ulong) ioremap(board->hw_base, SI1_ISA_WINDOW_LEN);
+               board->base = ioremap(board->hw_base, SI1_ISA_WINDOW_LEN);
                board->flags &= ~SX_BOARD_TYPE;
                board->flags |=  SI1_ISA_BOARD;
                board->irq = sx_irqmask ?-1:0;
@@ -2507,7 +2524,7 @@ static int __init sx_init(void)
                if (probe_si (board)) {
                        found++;
                } else {
-                       iounmap ((char *) (board->base));
+                       iounmap (board->base);
                }
        }
 
@@ -2527,10 +2544,10 @@ static int __init sx_init(void)
 
                        board->hw_base = (((inb(0xc01+eisa_slot) << 8) + inb(0xc00+eisa_slot)) << 16);
                        board->base2 =
-                       board->base = (ulong) ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
+                       board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
 
                        sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
-                       sx_dprintk(SX_DEBUG_PROBE, "base: %lx\n", board->base);
+                       sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
                        board->irq = inb(board->eisa_base+0xc02)>>4; 
                        sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
                        
@@ -2559,7 +2576,7 @@ static void __exit sx_exit (void)
        for (i = 0; i < SX_NBOARDS; i++) {
                board = &boards[i];
                if (board->flags & SX_BOARD_INITIALIZED) {
-                       sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %lx\n", board->base);
+                       sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %p\n", board->base);
                        /* The board should stop messing with us.
                           (actually I mean the interrupt) */
                        sx_reset (board);
@@ -2568,11 +2585,11 @@ static void __exit sx_exit (void)
 
                        /* It is safe/allowed to del_timer a non-active timer */
                        del_timer (& board->timer);
-                       iounmap ((char *) (board->base));
+                       iounmap(board->base);
                }
        }
        if (misc_deregister(&sx_fw_device) < 0) {
-               printk (KERN_INFO "sx: couldn't deregister firmware loader device\n");
+               printk (KERN_INFO "sx: couldn't deregister firmware loader devic\n");
        }
        sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized);
        if (sx_initialized)
index 9e65004..e01f83c 100644 (file)
@@ -32,8 +32,8 @@ struct sx_port {
 
 struct sx_board {
   int magic;
-  unsigned long base;
-  unsigned long base2;
+  void __iomem *base;
+  void __iomem *base2;
   unsigned long hw_base;
   int eisa_base;
   int port_base; /* Number of the first port */
index 0a1cc1d..73bfe95 100644 (file)
@@ -82,6 +82,7 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #include <linux/netdevice.h>
 
@@ -96,7 +97,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/types.h>
 #include <linux/termios.h>
 #include <linux/workqueue.h>
@@ -2139,16 +2140,15 @@ static void mgsl_flush_chars(struct tty_struct *tty)
  * Arguments:
  * 
  *     tty             pointer to tty information structure
- *     from_user       flag: 1 = from user process
  *     buf             pointer to buffer containing send data
  *     count           size of send data in bytes
  *     
  * Return Value:       number of characters written
  */
-static int mgsl_write(struct tty_struct * tty, int from_user,
+static int mgsl_write(struct tty_struct * tty,
                    const unsigned char *buf, int count)
 {
-       int     c, ret = 0, err;
+       int     c, ret = 0;
        struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
        unsigned long flags;
        
@@ -2185,20 +2185,7 @@ static int mgsl_write(struct tty_struct * tty, int from_user,
 
                        /* queue transmit frame request */
                        ret = count;
-                       if (from_user) {
-                               down(&tmp_buf_sem);
-                               COPY_FROM_USER(err,tmp_buf, buf, count);
-                               if (err) {
-                                       if ( debug_level >= DEBUG_LEVEL_INFO )
-                                               printk( "%s(%d):mgsl_write(%s) sync user buf copy failed\n",
-                                                       __FILE__,__LINE__,info->device_name);
-                                       ret = -EFAULT;
-                               } else
-                                       save_tx_buffer_request(info,tmp_buf,count);
-                               up(&tmp_buf_sem);
-                       }
-                       else
-                               save_tx_buffer_request(info,buf,count);
+                       save_tx_buffer_request(info,buf,count);
 
                        /* if we have sufficient tx dma buffers,
                         * load the next buffered tx request
@@ -2238,70 +2225,26 @@ static int mgsl_write(struct tty_struct * tty, int from_user,
                                        __FILE__,__LINE__,info->device_name);
                        ret = count;
                        info->xmit_cnt = count;
-                       if (from_user) {
-                               down(&tmp_buf_sem);
-                               COPY_FROM_USER(err,tmp_buf, buf, count);
-                               if (err) {
-                                       if ( debug_level >= DEBUG_LEVEL_INFO )
-                                               printk( "%s(%d):mgsl_write(%s) sync user buf copy failed\n",
-                                                       __FILE__,__LINE__,info->device_name);
-                                       ret = -EFAULT;
-                               } else
-                                       mgsl_load_tx_dma_buffer(info,tmp_buf,count);
-                               up(&tmp_buf_sem);
-                       }
-                       else
-                               mgsl_load_tx_dma_buffer(info,buf,count);
+                       mgsl_load_tx_dma_buffer(info,buf,count);
                }
        } else {
-               if (from_user) {
-                       down(&tmp_buf_sem);
-                       while (1) {
-                               c = min_t(int, count,
-                                       min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                           SERIAL_XMIT_SIZE - info->xmit_head));
-                               if (c <= 0)
-                                       break;
-
-                               COPY_FROM_USER(err,tmp_buf, buf, c);
-                               c -= err;
-                               if (!c) {
-                                       if (!ret)
-                                               ret = -EFAULT;
-                                       break;
-                               }
-                               spin_lock_irqsave(&info->irq_spinlock,flags);
-                               c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                              SERIAL_XMIT_SIZE - info->xmit_head));
-                               memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-                               info->xmit_head = ((info->xmit_head + c) &
-                                                  (SERIAL_XMIT_SIZE-1));
-                               info->xmit_cnt += c;
-                               spin_unlock_irqrestore(&info->irq_spinlock,flags);
-                               buf += c;
-                               count -= c;
-                               ret += c;
-                       }
-                       up(&tmp_buf_sem);
-               } else {
-                       while (1) {
-                               spin_lock_irqsave(&info->irq_spinlock,flags);
-                               c = min_t(int, count,
-                                       min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                           SERIAL_XMIT_SIZE - info->xmit_head));
-                               if (c <= 0) {
-                                       spin_unlock_irqrestore(&info->irq_spinlock,flags);
-                                       break;
-                               }
-                               memcpy(info->xmit_buf + info->xmit_head, buf, c);
-                               info->xmit_head = ((info->xmit_head + c) &
-                                                  (SERIAL_XMIT_SIZE-1));
-                               info->xmit_cnt += c;
+               while (1) {
+                       spin_lock_irqsave(&info->irq_spinlock,flags);
+                       c = min_t(int, count,
+                               min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                   SERIAL_XMIT_SIZE - info->xmit_head));
+                       if (c <= 0) {
                                spin_unlock_irqrestore(&info->irq_spinlock,flags);
-                               buf += c;
-                               count -= c;
-                               ret += c;
+                               break;
                        }
+                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
+                       info->xmit_head = ((info->xmit_head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       info->xmit_cnt += c;
+                       spin_unlock_irqrestore(&info->irq_spinlock,flags);
+                       buf += c;
+                       count -= c;
+                       ret += c;
                }
        }       
        
@@ -3259,8 +3202,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp)
        
        if (info->blocked_open) {
                if (info->close_delay) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(info->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
                }
                wake_up_interruptible(&info->open_wait);
        }
@@ -3326,8 +3268,7 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
        if ( info->params.mode == MGSL_MODE_HDLC ||
                info->params.mode == MGSL_MODE_RAW ) {
                while (info->tx_active) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(char_time);
+                       msleep_interruptible(jiffies_to_msecs(char_time));
                        if (signal_pending(current))
                                break;
                        if (timeout && time_after(jiffies, orig_jiffies + timeout))
@@ -3336,8 +3277,7 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
        } else {
                while (!(usc_InReg(info,TCSR) & TXSTATUS_ALL_SENT) &&
                        info->tx_enabled) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(char_time);
+                       msleep_interruptible(jiffies_to_msecs(char_time));
                        if (signal_pending(current))
                                break;
                        if (timeout && time_after(jiffies, orig_jiffies + timeout))
@@ -7200,8 +7140,7 @@ BOOLEAN mgsl_irq_test( struct mgsl_struct *info )
 
        EndTime=100;
        while( EndTime-- && !info->irq_occurred ) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(msecs_to_jiffies(10));
+               msleep_interruptible(10);
        }
        
        spin_lock_irqsave(&info->irq_spinlock,flags);
@@ -8150,9 +8089,7 @@ static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size)
 
        memcpy(skb_put(skb, size),buf,size);
 
-       skb->dev      = info->netdev;
-       skb->mac.raw  = skb->data;
-       skb->protocol = hdlc_type_trans(skb, skb->dev);
+       skb->protocol = hdlc_type_trans(skb, info->netdev);
 
        stats->rx_packets++;
        stats->rx_bytes += size;
index 66881e9..d812253 100644 (file)
@@ -554,10 +554,9 @@ static int wait_for_ready(time_t timeout)
            /* not ready and no exception && timeout not expired yet */
        while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && time_before(jiffies, spin_t)) {
                /* be `nice` to other processes on long operations... */
-               current->state = TASK_INTERRUPTIBLE;
                /* nap 0.30 sec between checks, */
                /* but could be woken up earlier by signals... */
-               schedule_timeout(3 * HZ / 10);
+               msleep_interruptible(300);
        }
 
        /* don't use jiffies for this test because it may have changed by now */
index dcfcef4..945b368 100644 (file)
@@ -83,15 +83,6 @@ struct viocharlpevent {
        u8 data[VIOCHAR_MAX_DATA];
 };
 
-/*
- * This is a place where we handle the distribution of memory
- * for copy_from_user() calls.  The buffer_available array is to
- * help us determine which buffer to use.
- */
-#define VIOCHAR_NUM_CFU_BUFFERS        7
-static struct viocharlpevent viocons_cfu_buffer[VIOCHAR_NUM_CFU_BUFFERS];
-static atomic_t viocons_cfu_buffer_available[VIOCHAR_NUM_CFU_BUFFERS];
-
 #define VIOCHAR_WINDOW         10
 #define VIOCHAR_HIGHWATERMARK  3
 
@@ -206,50 +197,6 @@ static inline int viotty_paranoia_check(struct port_info *pi,
        return 0;
 }
 
-/*
- * This function should ONLY be called once from viocons_init2
- */
-static void viocons_init_cfu_buffer(void)
-{
-       int i;
-
-       for (i = 1; i < VIOCHAR_NUM_CFU_BUFFERS; i++)
-               atomic_set(&viocons_cfu_buffer_available[i], 1);
-}
-
-static struct viocharlpevent *viocons_get_cfu_buffer(void)
-{
-       int i;
-
-       /*
-        * Grab the first available buffer.  It doesn't matter if we
-        * are interrupted during this array traversal as long as we
-        * get an available space.
-        */
-       for (i = 0; i < VIOCHAR_NUM_CFU_BUFFERS; i++)
-               if (atomic_dec_if_positive(&viocons_cfu_buffer_available[i])
-                               == 0 )
-                       return &viocons_cfu_buffer[i];
-       hvlog("\n\rviocons: viocons_get_cfu_buffer : no free buffers found");
-       return NULL;
-}
-
-static void viocons_free_cfu_buffer(struct viocharlpevent *buffer)
-{
-       int i;
-
-       i = buffer - &viocons_cfu_buffer[0];
-       if (i >= (sizeof(viocons_cfu_buffer) / sizeof(viocons_cfu_buffer[0]))) {
-               hvlog("\n\rviocons: viocons_free_cfu_buffer : buffer pointer not found in list.");
-               return;
-       }
-       if (atomic_read(&viocons_cfu_buffer_available[i]) != 0) {
-               hvlog("\n\rviocons: WARNING : returning unallocated cfu buffer.");
-               return;
-       }
-       atomic_set(&viocons_cfu_buffer_available[i], 1);
-}
-
 /*
  * Add data to our pending-send buffers.  
  *
@@ -438,15 +385,14 @@ static void send_buffers(struct port_info *pi)
  * NOTE: Don't use printk in here because it gets nastily recursive.  hvlog
  * can be used to log to the hypervisor buffer
  */
-static int internal_write(struct port_info *pi, const char *buf,
-                         size_t len, struct viocharlpevent *viochar)
+static int internal_write(struct port_info *pi, const char *buf, size_t len)
 {
        HvLpEvent_Rc hvrc;
        size_t bleft;
        size_t curlen;
        const char *curbuf;
        unsigned long flags;
-       int copy_needed = (viochar == NULL);
+       struct viocharlpevent *viochar;
 
        /*
         * Write to the hvlog of inbound data are now done prior to
@@ -462,25 +408,13 @@ static int internal_write(struct port_info *pi, const char *buf,
 
        spin_lock_irqsave(&consolelock, flags);
 
-       /*
-        * If the internal_write() was passed a pointer to a
-        * viocharlpevent then we don't need to allocate a new one
-        * (this is the case where we are internal_writing user space
-        * data).  If we aren't writing user space data then we need
-        * to get an event from viopath.
-        */
-       if (copy_needed) {
-               /* This one is fetched from the viopath data structure */
-               viochar = (struct viocharlpevent *)
-                       vio_get_event_buffer(viomajorsubtype_chario);
-               /* Make sure we got a buffer */
-               if (viochar == NULL) {
-                       spin_unlock_irqrestore(&consolelock, flags);
-                       hvlog("\n\rviocons: Can't get viochar buffer in internal_write().");
-                       return -EAGAIN;
-               }
-               initDataEvent(viochar, pi->lp);
+       viochar = vio_get_event_buffer(viomajorsubtype_chario);
+       if (viochar == NULL) {
+               spin_unlock_irqrestore(&consolelock, flags);
+               hvlog("\n\rviocons: Can't get vio buffer in internal_write().");
+               return -EAGAIN;
        }
+       initDataEvent(viochar, pi->lp);
 
        curbuf = buf;
        bleft = len;
@@ -493,25 +427,16 @@ static int internal_write(struct port_info *pi, const char *buf,
                        curlen = bleft;
 
                viochar->event.xCorrelationToken = pi->seq++;
-
-               if (copy_needed) {
-                       memcpy(viochar->data, curbuf, curlen);
-                       viochar->len = curlen;
-               }
-
+               memcpy(viochar->data, curbuf, curlen);
+               viochar->len = curlen;
                viochar->event.xSizeMinus1 =
                    offsetof(struct viocharlpevent, data) + curlen;
 
                hvrc = HvCallEvent_signalLpEvent(&viochar->event);
                if (hvrc) {
-                       spin_unlock_irqrestore(&consolelock, flags);
-                       if (copy_needed)
-                               vio_free_event_buffer(viomajorsubtype_chario, viochar);
-
                        hvlog("viocons: error sending event! %d\n", (int)hvrc);
-                       return len - bleft;
+                       goto out;
                }
-
                curbuf += curlen;
                bleft -= curlen;
        }
@@ -519,14 +444,9 @@ static int internal_write(struct port_info *pi, const char *buf,
        /* If we didn't send it all, buffer as much of it as we can. */
        if (bleft > 0)
                bleft -= buffer_add(pi, curbuf, bleft);
-       /*
-        * Since we grabbed it from the viopath data structure, return
-        * it to the data structure.
-        */
-       if (copy_needed)
-               vio_free_event_buffer(viomajorsubtype_chario, viochar);
+out:
+       vio_free_event_buffer(viomajorsubtype_chario, viochar);
        spin_unlock_irqrestore(&consolelock, flags);
-
        return len - bleft;
 }
 
@@ -603,18 +523,8 @@ static void viocons_write(struct console *co, const char *s, unsigned count)
 
        hvlogOutput(s, count);
 
-       if (!viopath_isactive(pi->lp)) {
-               /*
-                * This is a VERY noisy trace message in the case where the
-                * path manager is not active or in the case where this
-                * function is called prior to viocons initialization.  It is
-                * being commented out for the sake of a clear trace buffer.
-                */
-#if 0
-                hvlog("\n\rviocons_write: path not active to lp %d", pi->lp);
-#endif
+       if (!viopath_isactive(pi->lp))
                return;
-       }
 
        /* 
         * Any newline character found will cause a
@@ -627,17 +537,16 @@ static void viocons_write(struct console *co, const char *s, unsigned count)
                         * Newline found. Print everything up to and 
                         * including the newline
                         */
-                       internal_write(pi, &s[begin], index - begin + 1,
-                                       NULL);
+                       internal_write(pi, &s[begin], index - begin + 1);
                        begin = index + 1;
                        /* Emit a carriage return as well */
-                       internal_write(pi, &cr, 1, NULL);
+                       internal_write(pi, &cr, 1);
                }
        }
 
        /* If any characters left to write, write them now */
        if ((index - begin) > 0)
-               internal_write(pi, &s[begin], index - begin, NULL);
+               internal_write(pi, &s[begin], index - begin);
 }
 
 /*
@@ -721,11 +630,9 @@ static void viotty_close(struct tty_struct *tty, struct file *filp)
 /*
  * TTY Write method
  */
-static int viotty_write(struct tty_struct *tty, int from_user,
-                       const unsigned char *buf, int count)
+static int viotty_write(struct tty_struct *tty, const unsigned char *buf,
+               int count)
 {
-       int ret;
-       int total = 0;
        struct port_info *pi;
 
        pi = get_port_data(tty);
@@ -746,53 +653,10 @@ static int viotty_write(struct tty_struct *tty, int from_user,
         * viotty_write call and, since the viopath isn't active to this
         * partition, return count.
         */
-       if (!viopath_isactive(pi->lp)) {
-               /* Noisy trace.  Commented unless needed. */
-#if 0
-                hvlog("\n\rviotty_write: viopath NOT active for lp %d.",pi->lp);
-#endif
+       if (!viopath_isactive(pi->lp))
                return count;
-       }
 
-       /*
-        * If the viotty_write is invoked from user space we want to do the
-        * copy_from_user() into an event buffer from the cfu buffer before
-        * internal_write() is called because internal_write may need to buffer
-        * data which will need to grab a spin_lock and we shouldn't
-        * copy_from_user() while holding a spin_lock.  Should internal_write()
-        * not need to buffer data then it'll just use the event we created here
-        * rather than checking one out from vio_get_event_buffer().
-        */
-       if (from_user) {
-               struct viocharlpevent *viochar;
-               int curlen;
-               const char *curbuf = buf;
-
-               viochar = viocons_get_cfu_buffer();
-               if (viochar == NULL)
-                       return -EAGAIN;
-               initDataEvent(viochar, pi->lp);
-               while (count > 0) {
-                       if (count > VIOCHAR_MAX_DATA)
-                               curlen = VIOCHAR_MAX_DATA;
-                       else
-                               curlen = count;
-                       viochar->len = curlen;
-                       ret = copy_from_user(viochar->data, curbuf, curlen);
-                       if (ret)
-                               break;
-                       ret = internal_write(pi, viochar->data,
-                                       viochar->len, viochar);
-                       total += ret;
-                       if (ret != curlen)
-                               break;
-                       count -= curlen;
-                       curbuf += curlen;
-               }
-               viocons_free_cfu_buffer(viochar);
-       } else
-               total = internal_write(pi, buf, count, NULL);
-       return total;
+       return internal_write(pi, buf, count);
 }
 
 /*
@@ -811,7 +675,7 @@ static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
                hvlogOutput(&ch, 1);
 
        if (viopath_isactive(pi->lp))
-               internal_write(pi, &ch, 1, NULL);
+               internal_write(pi, &ch, 1);
 }
 
 /*
@@ -920,7 +784,7 @@ static void vioHandleOpenEvent(struct HvLpEvent *event)
                        atomic_set(aptr, 1);
                } else
                        printk(VIOCONS_KERN_WARN
-                              "wierd...got open ack without atomic\n");
+                              "weird...got open ack without atomic\n");
                return;
        }
 
@@ -1307,8 +1171,6 @@ static int __init viocons_init2(void)
                viotty_driver = NULL;
        }
 
-       viocons_init_cfu_buffer();
-
        unregister_console(&viocons_early);
        register_console(&viocons);
 
index ebcaf79..ab659d3 100644 (file)
@@ -25,9 +25,9 @@
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/hardware.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
index a6781de..82396e0 100644 (file)
@@ -22,9 +22,9 @@
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/hardware.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
@@ -216,7 +216,7 @@ static void __exit ixp4xx_wdt_exit(void)
 module_init(ixp4xx_wdt_init);
 module_exit(ixp4xx_wdt_exit);
 
-MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net">);
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
 MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
 
 module_param(heartbeat, int, 0);
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);
index 889f243..aa8eaca 100644 (file)
@@ -1,3 +1,32 @@
+config CPU_FREQ
+       bool "CPU Frequency scaling"
+       help
+         CPU Frequency scaling allows you to change the clock speed of 
+         CPUs on the fly. This is a nice method to save power, because 
+         the lower the CPU clock speed, the less power the CPU consumes.
+
+         Note that this driver doesn't automatically change the CPU
+         clock speed, you need to either enable a dynamic cpufreq governor
+         (see below) after boot, or use a userspace tool.
+
+         For details, take a look at <file:Documentation/cpu-freq>.
+
+         If in doubt, say N.
+
+config CPU_FREQ_DEBUG
+       bool "Enable CPUfreq debugging"
+       depends on CPU_FREQ
+       help
+         Say Y here to enable CPUfreq subsystem (including drivers)
+         debugging. You will need to activate it via the kernel
+         command line by passing
+            cpufreq.debug=<value>
+
+         To get <value>, add 
+              1 to activate CPUfreq core debugging,
+              2 to activate CPUfreq drivers debugging, and
+              4 to activate CPUfreq governor debugging
+
 config CPU_FREQ_PROC_INTF
        tristate "/proc/cpufreq interface (deprecated)"
        depends on CPU_FREQ && PROC_FS
@@ -33,7 +62,7 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
        help
          Use the CPUFreq governor 'userspace' as default. This allows
          you to set the CPU frequency manually or when an userspace 
-         programm shall be able to set the CPU dynamically without having
+         program shall be able to set the CPU dynamically without having
          to enable the userspace governor manually.
 
 endchoice
@@ -42,7 +71,7 @@ config CPU_FREQ_GOV_PERFORMANCE
        tristate "'performance' governor"
        depends on CPU_FREQ
        help
-         This cpufreq governors set the frequency statically to the
+         This cpufreq governor sets the frequency statically to the
          highest available CPU frequency.
 
          If in doubt, say Y.
@@ -51,7 +80,7 @@ config CPU_FREQ_GOV_POWERSAVE
        tristate "'powersave' governor"
        depends on CPU_FREQ
        help
-         Theis cpufreq governors set the frequency statically to the
+         This cpufreq governor sets the frequency statically to the
          lowest available CPU frequency.
 
          If in doubt, say Y.
@@ -61,14 +90,29 @@ config CPU_FREQ_GOV_USERSPACE
        depends on CPU_FREQ 
        help
          Enable this cpufreq governor when you either want to set the
-         CPU frequency manually or when an userspace programm shall
-          be able to set the CPU dynamically, like on LART 
+         CPU frequency manually or when an userspace program shall
+         be able to set the CPU dynamically, like on LART 
          <http://www.lart.tudelft.nl/>
 
          For details, take a look at <file:Documentation/cpu-freq/>.
 
          If in doubt, say Y.
 
+config CPU_FREQ_24_API
+       bool "/proc/sys/cpu/ interface (2.4. / OLD)"
+       depends on CPU_FREQ_GOV_USERSPACE
+       depends on SYSCTL
+       help
+         This enables the /proc/sys/cpu/ sysctl interface for controlling
+         the CPUFreq,"userspace" governor. This is the same interface
+         as known from the 2.4.-kernel patches for CPUFreq, and offers
+         the same functionality as long as "userspace" is the
+         selected governor for the specified CPU.
+       
+         For details, take a look at <file:Documentation/cpu-freq/>.
+
+         If in doubt, say N.
+
 config CPU_FREQ_GOV_ONDEMAND
        tristate "'ondemand' cpufreq policy governor"
        depends on CPU_FREQ
@@ -83,17 +127,3 @@ config CPU_FREQ_GOV_ONDEMAND
          For details, take a look at linux/Documentation/cpu-freq.
 
          If in doubt, say N.
-
-config CPU_FREQ_24_API
-       bool "/proc/sys/cpu/ interface (2.4. / OLD)"
-       depends on CPU_FREQ && SYSCTL && CPU_FREQ_GOV_USERSPACE
-       help
-         This enables the /proc/sys/cpu/ sysctl interface for controlling
-         the CPUFreq,"userspace" governor. This is the same interface
-         as known from the 2.4.-kernel patches for CPUFreq, and offers
-         the same functionality as long as "userspace" is the
-         selected governor for the specified CPU.
-       
-         For details, take a look at <file:Documentation/cpu-freq/>.
-
-         If in doubt, say N.
index a9320ae..bc31cac 100644 (file)
@@ -10,7 +10,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/smp.h>
@@ -26,7 +25,6 @@
 #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>
 
@@ -83,7 +81,7 @@ struct dbs_tuners {
        unsigned int            down_threshold;
 };
 
-struct dbs_tuners dbs_tuners_ins = {
+static 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,
@@ -101,10 +99,8 @@ static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
 }
 
 #define define_one_ro(_name)                                   \
-static struct freq_attr _name = {                              \
-       .attr = { .name = __stringify(_name), .mode = 0444 },   \
-       .show = show_##_name,                                   \
-}
+static struct freq_attr _name =                                \
+__ATTR(_name, 0444, show_##_name, NULL)
 
 define_one_ro(sampling_rate_max);
 define_one_ro(sampling_rate_min);
@@ -127,13 +123,13 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
        unsigned int input;
        int ret;
        ret = sscanf (buf, "%u", &input);
-       down(&dbs_sem);
        if (ret != 1 )
-               goto out;
+               return -EINVAL;
 
+       down(&dbs_sem);
        dbs_tuners_ins.sampling_down_factor = input;
-out:
        up(&dbs_sem);
+
        return count;
 }
 
@@ -143,13 +139,16 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
        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;
+       if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
+               up(&dbs_sem);
+               return -EINVAL;
+       }
 
        dbs_tuners_ins.sampling_rate = input;
-out:
        up(&dbs_sem);
+
        return count;
 }
 
@@ -159,15 +158,18 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
        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;
+                       input <= dbs_tuners_ins.down_threshold) {
+               up(&dbs_sem);
+               return -EINVAL;
+       }
 
        dbs_tuners_ins.up_threshold = input;
-out:
        up(&dbs_sem);
+
        return count;
 }
 
@@ -177,24 +179,24 @@ static ssize_t store_down_threshold(struct cpufreq_policy *unused,
        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;
+                       input >= dbs_tuners_ins.up_threshold) {
+               up(&dbs_sem);
+               return -EINVAL;
+       }
 
        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 define_one_rw(_name) \
+static struct freq_attr _name = \
+__ATTR(_name, 0644, show_##_name, store_##_name)
 
 define_one_rw(sampling_rate);
 define_one_rw(sampling_down_factor);
index f2348e7..8d536b4 100644 (file)
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "performance", msg)
+
+
 static int cpufreq_governor_performance(struct cpufreq_policy *policy,
                                        unsigned int event)
 {
        switch (event) {
        case CPUFREQ_GOV_START:
        case CPUFREQ_GOV_LIMITS:
+               dprintk("setting to %u kHz because of event %u\n", policy->max, event);
                __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
                break;
        default:
index ec85448..c85edda 100644 (file)
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "powersave", msg)
+
 static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
                                        unsigned int event)
 {
        switch (event) {
        case CPUFREQ_GOV_START:
        case CPUFREQ_GOV_LIMITS:
+               dprintk("setting to %u kHz because of event %u\n", policy->min, event);
                __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
                break;
        default:
index f0e6aaf..22e2ba6 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/init.h>
 #include <linux/cpufreq.h>
 
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
+
 /*********************************************************************
  *                     FREQUENCY TABLE HELPERS                       *
  *********************************************************************/
@@ -22,8 +24,12 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
 
        for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
                unsigned int freq = table[i].frequency;
-               if (freq == CPUFREQ_ENTRY_INVALID)
+               if (freq == CPUFREQ_ENTRY_INVALID) {
+                       dprintk("table entry %u is invalid, skipping\n", i);
+
                        continue;
+               }
+               dprintk("table entry %u: %u kHz, %u index\n", i, freq, table[i].index);
                if (freq < min_freq)
                        min_freq = freq;
                if (freq > max_freq)
@@ -48,6 +54,8 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
        unsigned int i = 0;
        unsigned int count = 0;
 
+       dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
+
        if (!cpu_online(policy->cpu))
                return -EINVAL;
 
@@ -72,6 +80,8 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
                                     policy->cpuinfo.min_freq, 
                                     policy->cpuinfo.max_freq);
 
+       dprintk("verification lead to (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
@@ -87,6 +97,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
        struct cpufreq_frequency_table suboptimal = { .index = ~0, };
        unsigned int i;
 
+       dprintk("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu);
+
        switch (relation) {
        case CPUFREQ_RELATION_H:
                optimal.frequency = 0;
@@ -142,7 +154,10 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
                *index = suboptimal.index;
        } else
                *index = optimal.index;
-       
+
+       dprintk("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
+               table[*index].index);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
@@ -175,7 +190,7 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
 }
 
 struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
-       .attr = { .name = "scaling_available_frequencies", .mode = 0444 },
+       .attr = { .name = "scaling_available_frequencies", .mode = 0444, .owner=THIS_MODULE },
        .show = show_available_freqs,
 };
 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
@@ -187,12 +202,14 @@ EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, 
                                      unsigned int cpu)
 {
+       dprintk("setting show_table for cpu %u to %p\n", cpu, table);
        show_table[cpu] = table;
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
 
 void cpufreq_frequency_table_put_attr(unsigned int cpu)
 {
+       dprintk("clearing show_table for cpu %u\n", cpu);
        show_table[cpu] = NULL;
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
index 33496df..ae92d17 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-obj-y := dio.o
+obj-y := dio.o dio-driver.o dio-sysfs.o
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);
+}
+
index 3bcc6f5..a620f7d 100644 (file)
@@ -1,5 +1,6 @@
-/* Code to support devices on the DIO (and eventually DIO-II) bus
+/* Code to support devices on the DIO and DIO-II bus
  * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Copyright (C) 2004 Jochen Friedrich <jochen@scram.de>
  * 
  * This code has basically these routines at the moment:
  * int dio_find(u_int deviceid)
@@ -9,9 +10,8 @@
  *    This means that framebuffers should pass it as 
  *    DIO_ENCODE_ID(DIO_ID_FBUFFER,DIO_ID2_TOPCAT)
  *    (or whatever); everybody else just uses DIO_ID_FOOBAR.
- * void *dio_scodetoviraddr(int scode)
- *    Return the virtual address corresponding to the given select code.
- *    NB: DIO-II devices will have to be mapped in in this routine!
+ * unsigned long dio_scodetophysaddr(int scode)
+ *    Return the physical address corresponding to the given select code.
  * int dio_scodetoipl(int scode)
  *    Every DIO card has a fixed interrupt priority level. This function 
  *    returns it, whatever it is.
  * This file is based on the way the Amiga port handles Zorro II cards, 
  * although we aren't so complicated...
  */
-#include <linux/config.h>
-#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
 #include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/dio.h>
 #include <linux/slab.h>                         /* kmalloc() */
-#include <linux/init.h>
-#include <asm/hwtest.h>                           /* hwreg_present() */
-#include <asm/io.h>                               /* readb() */
+#include <asm/uaccess.h>
+#include <asm/io.h>                             /* readb() */
+
+struct dio_bus dio_bus = {
+       .resources = {
+               /* DIO range */
+               { .name = "DIO mem", .start = 0x00600000, .end = 0x007fffff },
+               /* DIO-II range */
+               { .name = "DIO-II mem", .start = 0x01000000, .end = 0x1fffffff }
+       },
+       .name = "DIO bus"
+};
+
 /* not a real config option yet! */
 #define CONFIG_DIO_CONSTANTS
 
@@ -59,7 +71,7 @@ static struct dioname names[] =
         DIONAME(DCA0), DIONAME(DCA0REM), DIONAME(DCA1), DIONAME(DCA1REM),
         DIONAME(DCM), DIONAME(DCMREM),
         DIONAME(LAN),
-        DIONAME(FHPIB), DIONAME(NHPIB), DIONAME(IHPIB),
+        DIONAME(FHPIB), DIONAME(NHPIB),
         DIONAME(SCSI0), DIONAME(SCSI1), DIONAME(SCSI2), DIONAME(SCSI3),
         DIONAME(FBUFFER),
         DIONAME(PARALLEL), DIONAME(VME), DIONAME(DCL), DIONAME(DCLREM),
@@ -79,7 +91,7 @@ static struct dioname names[] =
 #define NUMNAMES (sizeof(names) / sizeof(struct dioname))
 
 static const char *unknowndioname 
-        = "unknown DIO board -- please email <pmaydell@chiark.greenend.org.uk>!";
+        = "unknown DIO board -- please email <linux-m68k@lists.linux-m68k.org>!";
 
 static const char *dio_getname(int id)
 {
@@ -88,7 +100,7 @@ static const char *dio_getname(int id)
         for (i = 0; i < NUMNAMES; i++)
                 if (names[i].id == id) 
                         return names[i].name;
-        
+
         return unknowndioname;
 }
 
@@ -99,70 +111,59 @@ static char dio_no_name[] = { 0 };
 
 #endif /* CONFIG_DIO_CONSTANTS */
 
-/* We represent all the DIO boards in the system with a linked list of these structs. */
-struct dioboard
-{
-        struct dioboard *next;                    /* link to next struct in list */
-        int ipl;                                  /* IPL of this board */
-        int configured;                           /* has this board been configured? */
-        int scode;                                /* select code of this board */
-        int id;                                   /* encoded ID */
-        const char *name;
-};
-
-static struct dioboard *blist = NULL;
-
-static int __init dio_find_slow(int deviceid)
+int __init dio_find(int deviceid)
 {
-       /* Called to find a DIO device before the full bus scan has run.  Basically
-         * only used by the console driver.
-         * We don't do the primary+secondary ID encoding thing here. Maybe we should.
-         * (that would break the topcat detection, though. I need to think about
-         * the whole primary/secondary ID thing.)
-         */
-       int scode;
-        u_char prid;
+       /* Called to find a DIO device before the full bus scan has run.
+        * Only used by the console driver.
+        */
+       int scode, id;
+       u_char prid, secid, i;
+       mm_segment_t fs;
 
-       for (scode = 0; scode < DIO_SCMAX; scode++)
-       {
+       for (scode = 0; scode < DIO_SCMAX; scode++) {
                void *va;
+               unsigned long pa;
 
                 if (DIO_SCINHOLE(scode))
                         continue;
-                
-                va = dio_scodetoviraddr(scode);
-                if (!va || !hwreg_present(va + DIO_IDOFF))
+
+                pa = dio_scodetophysaddr(scode);
+
+               if (!pa)
+                       continue;
+
+               if (scode < DIOII_SCBASE)
+                       va = (void *)(pa + DIO_VIRADDRBASE);
+               else
+                       va = ioremap(pa, PAGE_SIZE);
+
+               fs = get_fs();
+               set_fs(KERNEL_DS);
+
+                if (get_user(i, (unsigned char *)va + DIO_IDOFF)) {
+                       set_fs(fs);
+                       if (scode >= DIOII_SCBASE)
+                               iounmap(va);
                         continue;             /* no board present at that select code */
+               }
 
-                /* We aren't very likely to want to use this to get at the IHPIB,
-                 * but maybe it's returning the same ID as the card we do want...
-                 */
-                if (!DIO_ISIHPIB(scode))
-                        prid = DIO_ID(va);
-                else
-                        prid = DIO_ID_IHPIB;
+               set_fs(fs);
+               prid = DIO_ID(va);
 
-               if (prid == deviceid)
+                if (DIO_NEEDSSECID(prid)) {
+                        secid = DIO_SECID(va);
+                        id = DIO_ENCODE_ID(prid, secid);
+                } else
+                       id = prid;
+
+               if (id == deviceid) {
+                       if (scode >= DIOII_SCBASE)
+                               iounmap(va);
                        return scode;
+               }
        }
-       return 0;
-}
 
-/* Aargh: we use 0 for an error return code, but select code 0 exists!
- * FIXME (trivial, use -1, but requires changes to all the drivers :-< )
- */
-int dio_find(int deviceid)
-{
-       if (blist) 
-       {
-               /* fast way */
-               struct dioboard *b;
-               for (b = blist; b; b = b->next)
-                       if (b->id == deviceid && b->configured == 0)
-                               return b->scode;
-               return 0;
-       }
-       return dio_find_slow(deviceid);
+       return -1;
 }
 
 /* This is the function that scans the DIO space and works out what
@@ -170,58 +171,92 @@ int dio_find(int deviceid)
  */
 static int __init dio_init(void)
 {
-        int scode;
-        struct dioboard *b, *bprev = NULL;
-   
-        printk("Scanning for DIO devices...\n");
-        
+       int scode;
+       mm_segment_t fs;
+       int i;
+       struct dio_dev *dev;
+
+       if (!MACH_IS_HP300)
+               return 0;
+
+        printk(KERN_INFO "Scanning for DIO devices...\n");
+
+       /* Initialize the DIO bus */ 
+       INIT_LIST_HEAD(&dio_bus.devices);
+       strcpy(dio_bus.dev.bus_id, "dio");
+       device_register(&dio_bus.dev);
+
+       /* Request all resources */
+       dio_bus.num_resources = (hp300_model == HP_320 ? 1 : 2);
+       for (i = 0; i < dio_bus.num_resources; i++)
+               request_resource(&iomem_resource, &dio_bus.resources[i]);
+
+       /* Register all devices */
         for (scode = 0; scode < DIO_SCMAX; ++scode)
         {
                 u_char prid, secid = 0;        /* primary, secondary ID bytes */
                 u_char *va;
+               unsigned long pa;
                 
                 if (DIO_SCINHOLE(scode))
                         continue;
-                
-                va = dio_scodetoviraddr(scode);
-                if (!va || !hwreg_present(va + DIO_IDOFF))
+
+               pa = dio_scodetophysaddr(scode);
+
+               if (!pa)
+                       continue;
+
+               if (scode < DIOII_SCBASE)
+                       va = (void *)(pa + DIO_VIRADDRBASE);
+               else
+                       va = ioremap(pa, PAGE_SIZE);
+
+               fs = get_fs();
+               set_fs(KERNEL_DS);
+
+                if (get_user(i, (unsigned char *)va + DIO_IDOFF)) {
+                       set_fs(fs);
+                       if (scode >= DIOII_SCBASE)
+                               iounmap(va);
                         continue;              /* no board present at that select code */
+               }
+
+               set_fs(fs);
 
                 /* Found a board, allocate it an entry in the list */
-                b = kmalloc(sizeof(struct dioboard), GFP_KERNEL);
-                
-                /* read the ID byte(s) and encode if necessary. Note workaround 
-                 * for broken internal HPIB devices...
-                 */
-                if (!DIO_ISIHPIB(scode))
-                        prid = DIO_ID(va);
-                else 
-                        prid = DIO_ID_IHPIB;
-                
-                if (DIO_NEEDSSECID(prid))
-                {
+               dev = kmalloc(sizeof(struct dio_dev), GFP_KERNEL);
+               if (!dev)
+                       return 0;
+
+               memset(dev, 0, sizeof(struct dio_dev));
+               dev->bus = &dio_bus;
+               dev->dev.parent = &dio_bus.dev;
+               dev->dev.bus = &dio_bus_type;
+               dev->scode = scode;
+               dev->resource.start = pa;
+               dev->resource.end = pa + DIO_SIZE(scode, va);
+               sprintf(dev->dev.bus_id,"%02x", scode);
+
+                /* read the ID byte(s) and encode if necessary. */
+               prid = DIO_ID(va);
+
+                if (DIO_NEEDSSECID(prid)) {
                         secid = DIO_SECID(va);
-                        b->id = DIO_ENCODE_ID(prid, secid);
-                }
-                else
-                        b->id = prid;
-      
-                b->configured = 0;
-                b->scode = scode;
-                b->ipl = DIO_IPL(va);
-                b->name = dio_getname(b->id);
-                printk("select code %3d: ipl %d: ID %02X", scode, b->ipl, prid);
-                if (DIO_NEEDSSECID(b->id))
+                        dev->id = DIO_ENCODE_ID(prid, secid);
+                } else
+                        dev->id = prid;
+
+                dev->ipl = DIO_IPL(va);
+                strcpy(dev->name,dio_getname(dev->id));
+                printk(KERN_INFO "select code %3d: ipl %d: ID %02X", dev->scode, dev->ipl, prid);
+                if (DIO_NEEDSSECID(prid))
                         printk(":%02X", secid);
-                printk(": %s\n", b->name);
-                
-                b->next = NULL;
+                printk(": %s\n", dev->name);
 
-                if (bprev)
-                        bprev->next = b;
-                else
-                        blist = b;
-                bprev = b;
+               if (scode >= DIOII_SCBASE)
+                       iounmap(va);
+               device_register(&dev->dev);
+               dio_create_sysfs_dev_files(dev);
         }
        return 0;
 }
@@ -229,84 +264,16 @@ static int __init dio_init(void)
 subsys_initcall(dio_init);
 
 /* Bear in mind that this is called in the very early stages of initialisation
- * in order to get the virtual address of the serial port for the console...
+ * in order to get the address of the serial port for the console...
  */
-void *dio_scodetoviraddr(int scode)
+unsigned long dio_scodetophysaddr(int scode)
 {
-        if (scode > DIOII_SCBASE)
-        {
-                printk("dio_scodetoviraddr: don't support DIO-II yet!\n");
-                return 0;
-        }
-        else if (scode > DIO_SCMAX || scode < 0)
+        if (scode >= DIOII_SCBASE) {
+                return (DIOII_BASE + (scode - 132) * DIOII_DEVSIZE);
+        } else if (scode > DIO_SCMAX || scode < 0)
                 return 0;
         else if (DIO_SCINHOLE(scode))
                 return 0;
-        else if (DIO_ISIHPIB(scode))
-                return (void*)DIO_IHPIBADDR;
 
-        return (void*)(DIO_VIRADDRBASE + DIO_BASE + scode * 0x10000);
-}
-
-int dio_scodetoipl(int scode)
-{
-        struct dioboard *b;
-        for (b = blist; b; b = b->next)
-                if (b->scode == scode) 
-                        break;
-        
-        if (!b)
-        {
-                printk("dio_scodetoipl: bad select code %d\n", scode);
-                return 0;
-        }
-        else
-                return b->ipl;
-}
-
-const char *dio_scodetoname(int scode)
-{
-        struct dioboard *b;
-        for (b = blist; b; b = b->next)
-                if (b->scode == scode) 
-                        break;
-        
-        if (!b)
-        {
-                printk("dio_scodetoname: bad select code %d\n", scode);
-                return NULL;
-        }
-        else
-                return b->name;
-}
-
-void dio_config_board(int scode)
-{
-        struct dioboard *b;
-        for (b = blist; b; b = b->next)
-                if (b->scode == scode)
-                        break;
-   
-        if (!b) 
-                printk("dio_config_board: bad select code %d\n", scode);
-        else if (b->configured)
-                printk("dio_config_board: board at select code %d already configured\n", scode);
-        else
-                b->configured = 1;
-}
-
-void dio_unconfig_board(int scode)
-{
-        struct dioboard *b;
-        for (b = blist; b; b = b->next)
-                if (b->scode == scode) 
-                        break;
-   
-        if (!b) 
-                printk("dio_unconfig_board: bad select code %d\n", scode);
-        else if (!b->configured)
-                printk("dio_unconfig_board: board at select code %d not configured\n", 
-                      scode);
-        else 
-                b->configured = 0;
+        return (DIO_BASE + scode * DIO_DEVSIZE);
 }
index af825fc..6381ba5 100644 (file)
@@ -418,8 +418,8 @@ static int __init eisa_init (void)
        return 0;
 }
 
-module_param_array(enable_dev, int, enable_dev_count, 0444);
-module_param_array(disable_dev, int, disable_dev_count, 0444);
+module_param_array(enable_dev, int, &enable_dev_count, 0444);
+module_param_array(disable_dev, int, &disable_dev_count, 0444);
 
 postcore_initcall (eisa_init);
 
index 3f8b4c1..e7be415 100644 (file)
@@ -32,7 +32,7 @@ static char *version =
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/errno.h>
@@ -671,10 +671,10 @@ static inline void soc_init(struct sbus_dev *sdev, int no)
        cq[0].address = s->req_dvma;
        s->req[1].pool = s->req[0].pool + SOC_CQ_REQ0_SIZE;
        
-       s->req[0].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_REQ_OFFSET);
-       s->req[1].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_REQ_OFFSET + sizeof(soc_hw_cq));
-       s->rsp[0].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_RSP_OFFSET);
-       s->rsp[1].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_RSP_OFFSET + sizeof(soc_hw_cq));
+       s->req[0].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_REQ_OFFSET);
+       s->req[1].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_REQ_OFFSET + sizeof(soc_hw_cq));
+       s->rsp[0].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_RSP_OFFSET);
+       s->rsp[1].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_RSP_OFFSET + sizeof(soc_hw_cq));
        
        cq[1].address = cq[0].address + (SOC_CQ_REQ0_SIZE * sizeof(soc_req));
        cq[4].address = 1;
index a48a087..c4edefd 100644 (file)
@@ -260,7 +260,7 @@ typedef struct {
 } soc_port; 
 
 typedef struct {
-       soc_hw_cq               *hw_cq; /* Related XRAM cq */
+       soc_hw_cq               __iomem *hw_cq; /* Related XRAM cq */
        soc_req                 *pool;
        u8                      in;
        u8                      out;
index 5ee4dda..b2377db 100644 (file)
@@ -27,8 +27,8 @@ static char *version =
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/errno.h>
@@ -800,11 +800,11 @@ static inline void socal_init(struct sbus_dev *sdev, int no)
        s->rsp[1].pool = s->rsp[0].pool + SOCAL_CQ_RSP0_SIZE;
        s->rsp[2].pool = s->rsp[1].pool + SOCAL_CQ_RSP1_SIZE;
        
-       s->req[0].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_REQ_OFFSET);
-       s->req[1].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_REQ_OFFSET + sizeof(socal_hw_cq));
-       s->rsp[0].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_RSP_OFFSET);
-       s->rsp[1].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_RSP_OFFSET + sizeof(socal_hw_cq));
-       s->rsp[2].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_RSP_OFFSET + 2 * sizeof(socal_hw_cq));
+       s->req[0].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_REQ_OFFSET);
+       s->req[1].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_REQ_OFFSET + sizeof(socal_hw_cq));
+       s->rsp[0].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_RSP_OFFSET);
+       s->rsp[1].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_RSP_OFFSET + sizeof(socal_hw_cq));
+       s->rsp[2].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_RSP_OFFSET + 2 * sizeof(socal_hw_cq));
        
        cq[1].address = cq[0].address + (SOCAL_CQ_REQ0_SIZE * sizeof(socal_req));
        cq[4].address = cq[1].address + (SOCAL_CQ_REQ1_SIZE * sizeof(socal_req));
index 2ff386b..774edf6 100644 (file)
@@ -281,7 +281,7 @@ typedef struct {
 } socal_port; 
 
 typedef struct {
-       socal_hw_cq             *hw_cq; /* Related XRAM cq */
+       socal_hw_cq             __iomem *hw_cq; /* Related XRAM cq */
        socal_req               *pool;
        u8                      in;
        u8                      out;
index 09e4f68..ca751f5 100644 (file)
 #include <linux/acpi.h>
 #include <linux/console.h>
 #include <linux/efi.h>
-#include <linux/tty.h>
 #include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <asm/io.h>
-#include <asm/serial.h>
 #include "pcdp.h"
 
-static inline int
-uart_irq_supported(int rev, struct pcdp_uart *uart)
-{
-       if (rev < 3)
-               return uart->pci_func & PCDP_UART_IRQ;
-       return uart->flags & PCDP_UART_IRQ;
-}
-
-static inline int
-uart_pci(int rev, struct pcdp_uart *uart)
-{
-       if (rev < 3)
-               return uart->pci_func & PCDP_UART_PCI;
-       return uart->flags & PCDP_UART_PCI;
-}
-
-static inline int
-uart_active_high_low(int rev, struct pcdp_uart *uart)
-{
-       if (uart_pci(rev, uart) || uart->flags & PCDP_UART_ACTIVE_LOW)
-               return ACPI_ACTIVE_LOW;
-       return ACPI_ACTIVE_HIGH;
-}
-
-static inline int
-uart_edge_level(int rev, struct pcdp_uart *uart)
-{
-       if (uart_pci(rev, uart))
-               return ACPI_LEVEL_SENSITIVE;
-       if (rev < 3 || uart->flags & PCDP_UART_EDGE_SENSITIVE)
-               return ACPI_EDGE_SENSITIVE;
-       return ACPI_LEVEL_SENSITIVE;
-}
-
-static void __init
-setup_serial_console(int rev, struct pcdp_uart *uart)
+static int __init
+setup_serial_console(struct pcdp_uart *uart)
 {
 #ifdef CONFIG_SERIAL_8250_CONSOLE
-       struct uart_port port;
-       static char options[16];
-       int mapsize = 64;
-
-       memset(&port, 0, sizeof(port));
-       port.uartclk = uart->clock_rate;
-       if (!port.uartclk)      /* some FW doesn't supply this */
-               port.uartclk = BASE_BAUD * 16;
-
-       if (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-               port.mapbase = uart->addr.address;
-               port.membase = ioremap(port.mapbase, mapsize);
-               if (!port.membase) {
-                       printk(KERN_ERR "%s: couldn't ioremap 0x%lx-0x%lx\n",
-                               __FUNCTION__, port.mapbase, port.mapbase + mapsize);
-                       return;
-               }
-               port.iotype = UPIO_MEM;
-       } else if (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
-               port.iobase = uart->addr.address;
-               port.iotype = UPIO_PORT;
-       } else
-               return;
-
-       switch (uart->pci_prog_intfc) {
-               case 0x0: port.type = PORT_8250;    break;
-               case 0x1: port.type = PORT_16450;   break;
-               case 0x2: port.type = PORT_16550;   break;
-               case 0x3: port.type = PORT_16650;   break;
-               case 0x4: port.type = PORT_16750;   break;
-               case 0x5: port.type = PORT_16850;   break;
-               case 0x6: port.type = PORT_16C950;  break;
-               default:  port.type = PORT_UNKNOWN; break;
-       }
-
-       port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-
-       if (uart_irq_supported(rev, uart)) {
-               port.irq = acpi_register_gsi(uart->gsi,
-                       uart_active_high_low(rev, uart),
-                       uart_edge_level(rev, uart));
-               port.flags |= UPF_AUTO_IRQ;  /* some FW reported wrong GSI */
-               if (uart_pci(rev, uart))
-                       port.flags |= UPF_SHARE_IRQ;
-       }
-
-       if (early_serial_setup(&port) < 0)
-               return;
+       int mmio;
+       static char options[64];
 
-       snprintf(options, sizeof(options), "%lun%d", uart->baud,
+       mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
+       snprintf(options, sizeof(options), "console=uart,%s,0x%lx,%lun%d",
+               mmio ? "mmio" : "io", uart->addr.address, uart->baud,
                uart->bits ? uart->bits : 8);
-       add_preferred_console("ttyS", port.line, options);
 
-       printk(KERN_INFO "PCDP: serial console at %s 0x%lx (ttyS%d, options %s)\n",
-               port.iotype == UPIO_MEM ? "MMIO" : "I/O",
-               uart->addr.address, port.line, options);
+       return early_serial_console_init(options);
+#else
+       return -ENODEV;
 #endif
 }
 
-static void __init
+static int __init
 setup_vga_console(struct pcdp_vga *vga)
 {
-#ifdef CONFIG_VT
-#ifdef CONFIG_VGA_CONSOLE
+#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
        if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
                printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
-               return;
+               return -ENODEV;
        }
 
        conswitchp = &vga_con;
        printk(KERN_INFO "PCDP: VGA console\n");
-#endif
+       return 0;
+#else
+       return -ENODEV;
 #endif
 }
 
-void __init
+int __init
 efi_setup_pcdp_console(char *cmdline)
 {
        struct pcdp *pcdp;
@@ -144,20 +62,25 @@ efi_setup_pcdp_console(char *cmdline)
 
        pcdp = efi.hcdp;
        if (!pcdp)
-               return;
+               return -ENODEV;
 
-       printk(KERN_INFO "PCDP: v%d at 0x%p\n", pcdp->rev, pcdp);
+       printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, __pa(pcdp));
 
-       if (pcdp->rev < 3) {
-               if (strstr(cmdline, "console=ttyS0") || efi_uart_console_only())
+       if (strstr(cmdline, "console=hcdp")) {
+               if (pcdp->rev < 3)
                        serial = 1;
+       } else if (strstr(cmdline, "console=")) {
+               printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n");
+               return -ENODEV;
        }
 
+       if (pcdp->rev < 3 && efi_uart_console_only())
+               serial = 1;
+
        for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
                if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
                        if (uart->type == PCDP_CONSOLE_UART) {
-                               setup_serial_console(pcdp->rev, uart);
-                               return;
+                               return setup_serial_console(uart);
                        }
                }
        }
@@ -168,11 +91,12 @@ efi_setup_pcdp_console(char *cmdline)
             dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
                if (dev->flags & PCDP_PRIMARY_CONSOLE) {
                        if (dev->type == PCDP_CONSOLE_VGA) {
-                               setup_vga_console((struct pcdp_vga *) dev);
-                               return;
+                               return setup_vga_console((struct pcdp_vga *) dev);
                        }
                }
        }
+
+       return -ENODEV;
 }
 
 #ifdef CONFIG_IA64_EARLY_PRINTK_UART
index 7405aac..1b2c67c 100644 (file)
@@ -107,14 +107,6 @@ static int wait_for_bb(struct i2c_algo_iic_data *adap)
        return(timeout<=0);
 }
 
-/*
- * Puts this process to sleep for a period equal to timeout 
- */
-static inline void iic_sleep(unsigned long timeout)
-{
-       schedule_timeout( timeout * HZ);
-}
-
 /* After we issue a transaction on the IIC bus, this function
  * is called.  It puts this process to sleep until we get an interrupt from
  * from the controller telling us that the transaction we requested in complete.
index 38092b7..aaad686 100644 (file)
@@ -249,7 +249,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
                        break;
 
                case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
-                       DEB2("NOT ACK recieved after SLA+W\n");
+                       DEB2("NOT ACK received after SLA+W\n");
                        pca_stop(adap);
                        return -EREMOTEIO;
 
@@ -277,7 +277,7 @@ static int pca_xfer(struct i2c_adapter *i2c_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");
+                       DEB2("NOT ACK received after data byte\n");
                        return -EREMOTEIO;
 
                case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
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);
index 275da79..7480fd0 100644 (file)
@@ -120,6 +120,8 @@ static struct pci_device_id hydra_ids[] = {
        { 0, }
 };
 
+MODULE_DEVICE_TABLE (pci, hydra_ids);
+
 static int __devinit hydra_probe(struct pci_dev *dev,
                                 const struct pci_device_id *id)
 {
@@ -166,7 +168,7 @@ static struct pci_driver hydra_driver = {
 
 static int __init i2c_hydra_init(void)
 {
-       return pci_module_init(&hydra_driver);
+       return pci_register_driver(&hydra_driver);
 }
 
 
index 46bd566..ef358bd 100644 (file)
@@ -70,7 +70,7 @@
 #define CYCLE_DELAY            10
 #define TIMEOUT                        (HZ / 2)
 
-static void *ioaddr;
+static void __iomem *ioaddr;
 
 /* The i810 GPIO registers have individual masks for each bit
    so we never have to read before writing. Nice. */
@@ -201,6 +201,8 @@ static struct pci_device_id i810_ids[] __devinitdata = {
        { 0, },
 };
 
+MODULE_DEVICE_TABLE (pci, i810_ids);
+
 static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int retval;
@@ -239,7 +241,7 @@ static struct pci_driver i810_driver = {
 
 static int __init i2c_i810_init(void)
 {
-       return pci_module_init(&i810_driver);
+       return pci_register_driver(&i810_driver);
 }
 
 static void __exit i2c_i810_exit(void)
index d365498..d819a95 100644 (file)
@@ -45,7 +45,7 @@ struct iic_regs {
 
 struct ibm_iic_private {
        struct i2c_adapter adap;
-       volatile struct iic_regs *vaddr;
+       volatile struct iic_regs __iomem *vaddr;
        wait_queue_head_t wq;
        int idx;
        int irq;
index da926a6..6263811 100644 (file)
@@ -62,6 +62,7 @@ static int own;
 static struct iic_ite gpi;
 static wait_queue_head_t iic_wait;
 static int iic_pending;
+static spinlock_t lock;
 
 /* ----- local functions ----------------------------------------------        */
 
@@ -108,6 +109,7 @@ static int iic_ite_getclock(void *data)
 static void iic_ite_waitforpin(void) {
 
    int timeout = 2;
+   long flags;
 
    /* If interrupts are enabled (which they are), then put the process to
     * sleep.  This process will be awakened by two events -- either the
@@ -116,24 +118,36 @@ static void iic_ite_waitforpin(void) {
     * of time and return.
     */
    if (gpi.iic_irq > 0) {
-       cli();
+       spin_lock_irqsave(&lock, flags);
        if (iic_pending == 0) {
-               interruptible_sleep_on_timeout(&iic_wait, timeout*HZ );
-       } else
+               spin_unlock_irqrestore(&lock, flags);
+               if (interruptible_sleep_on_timeout(&iic_wait, timeout*HZ)) {
+                       spin_lock_irqsave(&lock, flags);
+                       if (iic_pending == 1) {
+                               iic_pending = 0;
+                       }
+                       spin_unlock_irqrestore(&lock, flags);
+               }
+       } else {
                iic_pending = 0;
-       sti();
+               spin_unlock_irqrestore(&lock, flags);
+       }
    } else {
       udelay(100);
    }
 }
 
 
-static void iic_ite_handler(int this_irq, void *dev_id, struct pt_regs *regs) 
+static irqreturn_t iic_ite_handler(int this_irq, void *dev_id,
+                                                       struct pt_regs *regs)
 {
-       
-   iic_pending = 1;
+       spin_lock(&lock);
+       iic_pending = 1;
+       spin_unlock(&lock);
+
+       wake_up_interruptible(&iic_wait);
 
-   wake_up_interruptible(&iic_wait);
+       return IRQ_HANDLED;
 }
 
 
@@ -221,6 +235,7 @@ static int __init iic_ite_init(void)
 
        iic_ite_data.data = (void *)piic;
        init_waitqueue_head(&iic_wait);
+       spin_lock_init(&lock);
        if (iic_hw_resrc_init() == 0) {
                if (i2c_iic_add_bus(&iic_ite_ops) < 0)
                        return -ENODEV;
index ecc279d..c5022e1 100644 (file)
@@ -52,7 +52,7 @@ typedef enum {
 struct keywest_iface
 {
        struct device_node      *node;
-       unsigned long           base;
+       void __iomem *          base;
        unsigned                bsteps;
        int                     irq;
        spinlock_t              lock;
@@ -89,13 +89,13 @@ struct keywest_chan
 
 static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg)
 {
-       return in_8(((volatile u8 *)iface->base)
+       return in_8(iface->base
                + (((unsigned)reg) << iface->bsteps));
 }
 
 static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val)
 {
-       out_8(((volatile u8 *)iface->base)
+       out_8(iface->base
                + (((unsigned)reg) << iface->bsteps), val);
        (void)__read_reg(iface, reg_subaddr);
 }
index f77245e..ca9e203 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/ocp.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 
 #define MPC_I2C_ADDR  0x00
 #define MPC_I2C_FDR    0x04
@@ -91,9 +92,9 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
                x = readb(i2c->base + MPC_I2C_SR);
                writeb(0, i2c->base + MPC_I2C_SR);
        } else {
+               set_current_state(TASK_INTERRUPTIBLE);
                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;
@@ -104,9 +105,9 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
                                result = -EIO;
                                break;
                        }
-                       schedule_timeout(timeout);
+                       msleep_interruptible(jiffies_to_msecs(timeout));
                }
-               current->state = TASK_RUNNING;
+               set_current_state(TASK_RUNNING);
                remove_wait_queue(&i2c->queue, &wait);
                x = i2c->interrupt;
                i2c->interrupt = 0;
index 9552e53..f580456 100644 (file)
@@ -68,7 +68,7 @@
 #define MAX_BUSSES     2
 
 struct s_i2c_bus {
-       void    *mmvga;
+       void __iomem *mmvga;
        int     i2c_reg;
        int     adap_ok;
        struct i2c_adapter              adap;
@@ -76,7 +76,7 @@ struct s_i2c_bus {
 };
 
 struct s_i2c_chip {
-       void    *mmio;
+       void __iomem *mmio;
        struct s_i2c_bus        i2c_bus[MAX_BUSSES];
 };
 
@@ -181,7 +181,7 @@ static int bit_s3via_getsda(void *bus)
 /*
  * adapter initialisation
  */
-static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, u8 *mmvga, u32 i2c_reg)
+static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iomem *mmvga, u32 i2c_reg)
 {
        int ret;
        p->adap.owner     = THIS_MODULE;
@@ -228,7 +228,7 @@ static void prosavage_remove(struct pci_dev *dev)
 
                ret = i2c_bit_del_bus(&chip->i2c_bus[i].adap);
                if (ret) {
-                       dev_err(&dev->dev, "%s not removed\n",
+                       dev_err(&dev->dev, "%s not removed\n",
                                chip->i2c_bus[i].adap.name);
                }
        }
@@ -298,7 +298,7 @@ static int __devinit prosavage_probe(struct pci_dev *dev, const struct pci_devic
        }
        return 0;
 err_adap:
-       dev_err(&dev->dev, "%s failed\n", bus->adap.name);
+       dev_err(&dev->dev, "%s failed\n", bus->adap.name);
        prosavage_remove(dev);
        return ret;
 }
@@ -313,6 +313,8 @@ static struct pci_device_id prosavage_pci_tbl[] = {
        { 0, },
 };
 
+MODULE_DEVICE_TABLE (pci, prosavage_pci_tbl);
+
 static struct pci_driver prosavage_driver = {
        .name           =       "prosavage_smbus",
        .id_table       =       prosavage_pci_tbl,
@@ -322,7 +324,7 @@ static struct pci_driver prosavage_driver = {
 
 static int __init i2c_prosavage_init(void)
 {
-       return pci_module_init(&prosavage_driver);
+       return pci_register_driver(&prosavage_driver);
 }
 
 static void __exit i2c_prosavage_exit(void)
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");
index 52d5194..092d032 100644 (file)
@@ -73,7 +73,7 @@
 #define TIMEOUT                        (HZ / 2)
 
 
-static void *ioaddr;
+static void __iomem *ioaddr;
 
 /* The sav GPIO registers don't have individual masks for each bit
    so we always have to read before writing. */
@@ -157,6 +157,8 @@ static struct pci_device_id savage4_ids[] __devinitdata = {
        { 0, }
 };
 
+MODULE_DEVICE_TABLE (pci, savage4_ids);
+
 static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int retval;
@@ -186,7 +188,7 @@ static struct pci_driver savage4_driver = {
 
 static int __init i2c_savage4_init(void)
 {
-       return pci_module_init(&savage4_driver);
+       return pci_register_driver(&savage4_driver);
 }
 
 static void __exit i2c_savage4_exit(void)
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);
+
index 711eaa2..4f41088 100644 (file)
  * NE1619 has two possible addresses: 0x2c and 0x2d.
  */
 
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
@@ -153,7 +151,7 @@ struct adm1025_data {
  * Internal variables
  */
 
-static int adm1025_id = 0;
+static int adm1025_id;
 
 /*
  * Sysfs stuff
@@ -212,8 +210,8 @@ static ssize_t set_in##offset##_min(struct device *dev, const char *buf, \
 { \
        struct i2c_client *client = to_i2c_client(dev); \
        struct adm1025_data *data = i2c_get_clientdata(client); \
-       data->in_min[offset] = IN_TO_REG(simple_strtol(buf, NULL, 10), \
-                              in_scale[offset]); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \
        i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \
                                  data->in_min[offset]); \
        return count; \
@@ -223,8 +221,8 @@ static ssize_t set_in##offset##_max(struct device *dev, const char *buf, \
 { \
        struct i2c_client *client = to_i2c_client(dev); \
        struct adm1025_data *data = i2c_get_clientdata(client); \
-       data->in_max[offset] = IN_TO_REG(simple_strtol(buf, NULL, 10), \
-                              in_scale[offset]); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \
        i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \
                                  data->in_max[offset]); \
        return count; \
@@ -246,7 +244,8 @@ static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \
 { \
        struct i2c_client *client = to_i2c_client(dev); \
        struct adm1025_data *data = i2c_get_clientdata(client); \
-       data->temp_min[offset-1] = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->temp_min[offset-1] = TEMP_TO_REG(val); \
        i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \
                                  data->temp_min[offset-1]); \
        return count; \
@@ -256,7 +255,8 @@ static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
 { \
        struct i2c_client *client = to_i2c_client(dev); \
        struct adm1025_data *data = i2c_get_clientdata(client); \
-       data->temp_max[offset-1] = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->temp_max[offset-1] = TEMP_TO_REG(val); \
        i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \
                                  data->temp_max[offset-1]); \
        return count; \
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);
index 23c323e..69f4d1e 100644 (file)
 #define ADM1031_CONF2_TEMP_ENABLE(chan)        (0x10 << (chan))
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
 SENSORS_INSMOD_2(adm1030, adm1031);
@@ -298,12 +296,12 @@ set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr)
 #define fan_auto_channel_offset(offset)                                                \
 static ssize_t show_fan_auto_channel_##offset (struct device *dev, char *buf)  \
 {                                                                              \
-       return show_fan_auto_channel(dev, buf, 0x##offset - 1);                 \
+       return show_fan_auto_channel(dev, buf, offset - 1);                     \
 }                                                                              \
 static ssize_t set_fan_auto_channel_##offset (struct device *dev,              \
        const char *buf, size_t count)                                          \
 {                                                                              \
-       return set_fan_auto_channel(dev, buf, count, 0x##offset - 1);           \
+       return set_fan_auto_channel(dev, buf, count, offset - 1);               \
 }                                                                              \
 static DEVICE_ATTR(auto_fan##offset##_channel, S_IRUGO | S_IWUSR,              \
                   show_fan_auto_channel_##offset,                              \
@@ -365,25 +363,25 @@ set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr)
 #define auto_temp_reg(offset)                                                  \
 static ssize_t show_auto_temp_##offset##_off (struct device *dev, char *buf)   \
 {                                                                              \
-       return show_auto_temp_off(dev, buf, 0x##offset - 1);                    \
+       return show_auto_temp_off(dev, buf, offset - 1);                        \
 }                                                                              \
 static ssize_t show_auto_temp_##offset##_min (struct device *dev, char *buf)   \
 {                                                                              \
-       return show_auto_temp_min(dev, buf, 0x##offset - 1);                    \
+       return show_auto_temp_min(dev, buf, offset - 1);                        \
 }                                                                              \
 static ssize_t show_auto_temp_##offset##_max (struct device *dev, char *buf)   \
 {                                                                              \
-       return show_auto_temp_max(dev, buf, 0x##offset - 1);                    \
+       return show_auto_temp_max(dev, buf, offset - 1);                        \
 }                                                                              \
 static ssize_t set_auto_temp_##offset##_min (struct device *dev,               \
                                             const char *buf, size_t count)     \
 {                                                                              \
-       return set_auto_temp_min(dev, buf, count, 0x##offset - 1);              \
+       return set_auto_temp_min(dev, buf, count, offset - 1);          \
 }                                                                              \
 static ssize_t set_auto_temp_##offset##_max (struct device *dev,               \
                                             const char *buf, size_t count)     \
 {                                                                              \
-       return set_auto_temp_max(dev, buf, count, 0x##offset - 1);              \
+       return set_auto_temp_max(dev, buf, count, offset - 1);          \
 }                                                                              \
 static DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO,                           \
                   show_auto_temp_##offset##_off, NULL);                        \
@@ -429,14 +427,14 @@ set_pwm(struct device *dev, const char *buf, size_t count, int nr)
 #define pwm_reg(offset)                                                        \
 static ssize_t show_pwm_##offset (struct device *dev, char *buf)       \
 {                                                                      \
-       return show_pwm(dev, buf, 0x##offset - 1);                      \
+       return show_pwm(dev, buf, offset - 1);                  \
 }                                                                      \
 static ssize_t set_pwm_##offset (struct device *dev,                   \
                                 const char *buf, size_t count)         \
 {                                                                      \
-       return set_pwm(dev, buf, count, 0x##offset - 1);                \
+       return set_pwm(dev, buf, count, offset - 1);            \
 }                                                                      \
-static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR,               \
+static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,                     \
                   show_pwm_##offset, set_pwm_##offset)
 
 pwm_reg(1);
@@ -565,25 +563,25 @@ set_fan_div(struct device *dev, const char *buf, size_t count, int nr)
 #define fan_offset(offset)                                             \
 static ssize_t show_fan_##offset (struct device *dev, char *buf)       \
 {                                                                      \
-       return show_fan(dev, buf, 0x##offset - 1);                      \
+       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, 0x##offset - 1);                  \
+       return show_fan_min(dev, buf, offset - 1);                      \
 }                                                                      \
 static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \
 {                                                                      \
-       return show_fan_div(dev, buf, 0x##offset - 1);                  \
+       return show_fan_div(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, 0x##offset - 1);            \
+       return set_fan_min(dev, buf, count, 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);            \
+       return set_fan_div(dev, buf, count, offset - 1);                \
 }                                                                      \
 static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset,    \
                   NULL);                                               \
@@ -675,34 +673,34 @@ set_temp_crit(struct device *dev, const char *buf, size_t count, int nr)
 #define temp_reg(offset)                                                       \
 static ssize_t show_temp_##offset (struct device *dev, char *buf)              \
 {                                                                              \
-       return show_temp(dev, buf, 0x##offset - 1);                             \
+       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, 0x##offset - 1);                         \
+       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, 0x##offset - 1);                         \
+       return show_temp_max(dev, buf, offset - 1);                             \
 }                                                                              \
 static ssize_t show_temp_##offset##_crit (struct device *dev, char *buf)       \
 {                                                                              \
-       return show_temp_crit(dev, buf, 0x##offset - 1);                        \
+       return show_temp_crit(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, 0x##offset - 1);                   \
+       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, 0x##offset - 1);                   \
+       return set_temp_max(dev, buf, count, 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, 0x##offset - 1);                  \
+       return set_temp_crit(dev, buf, count, offset - 1);                      \
 }                                                                              \
 static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset,          \
                   NULL);                                                       \
@@ -799,7 +797,7 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
        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_fan1_pwm);
+       device_create_file(&new_client->dev, &dev_attr_pwm1);
        device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel);
        device_create_file(&new_client->dev, &dev_attr_temp1_input);
        device_create_file(&new_client->dev, &dev_attr_temp1_min);
@@ -826,7 +824,7 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
                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_fan2_pwm);
+               device_create_file(&new_client->dev, &dev_attr_pwm2);
                device_create_file(&new_client->dev,
                                   &dev_attr_auto_fan2_channel);
                device_create_file(&new_client->dev, &dev_attr_temp3_input);
index 3aa7298..bb0df88 100644 (file)
 #include "lm75.h"
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x48, 0x4f, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+                                       0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
 SENSORS_INSMOD_1(ds1621);
@@ -96,7 +95,7 @@ static struct i2c_driver ds1621_driver = {
        .detach_client  = ds1621_detach_client,
 };
 
-static int ds1621_id = 0;
+static int ds1621_id;
 
 /* All registers are word-sized, except for the configuration register.
    DS1621 uses a high-byte first convention, which is exactly opposite to
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);
index a6fc781..71cf379 100644 (file)
 
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x48, 0x4b, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END };
 static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
 SENSORS_INSMOD_1(lm77);
@@ -83,7 +81,7 @@ static struct i2c_driver lm77_driver = {
        .detach_client  = lm77_detach_client,
 };
 
-static int lm77_id = 0;
+static int lm77_id;
 
 /* straight from the datasheet */
 #define LM77_TEMP_MIN (-55000)
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);
index 0f8a5ac..bc7e22f 100644 (file)
 #include <linux/i2c-sensor.h>
 
 
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b,
-                                               0x4c, 0x4e, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
+                                       0x29, 0x2a, 0x2b,
+                                       0x4c, 0x4d, 0x4e,
+                                       I2C_CLIENT_END };
 static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
 
 /*
  * Insmod parameters
@@ -120,7 +120,7 @@ struct max1619_data {
  * Internal variables
  */
 
-static int max1619_id = 0;
+static int max1619_id;
 
 /*
  * Sysfs stuff
@@ -145,7 +145,8 @@ static ssize_t set_##value(struct device *dev, const char *buf, \
 { \
        struct i2c_client *client = to_i2c_client(dev); \
        struct max1619_data *data = i2c_get_clientdata(client); \
-       data->value = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->value = TEMP_TO_REG(val); \
        i2c_smbus_write_byte_data(client, reg, data->value); \
        return count; \
 }
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);
index 78c6693..7943938 100644 (file)
 #include <linux/i2c-sensor.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x20, 0x27, 0x38, 0x3f, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+                                       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+                                       I2C_CLIENT_END };
 static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
 SENSORS_INSMOD_2(pcf8574, pcf8574a);
@@ -77,7 +77,7 @@ static struct i2c_driver pcf8574_driver = {
        .detach_client  = pcf8574_detach_client,
 };
 
-static int pcf8574_id = 0;
+static int pcf8574_id;
 
 /* following are the sysfs callback functions */
 static ssize_t show_read(struct device *dev, char *buf)
index d63e06d..8f3b858 100644 (file)
 #include <linux/i2c-sensor.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x48, 0x4f, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+                                       0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
 SENSORS_INSMOD_1(pcf8591);
@@ -99,7 +98,7 @@ static struct i2c_driver pcf8591_driver = {
        .detach_client  = pcf8591_detach_client,
 };
 
-static int pcf8591_id = 0;
+static int pcf8591_id;
 
 /* following are the sysfs callback functions */
 #define show_in_channel(channel)                                       \
index 078c65f..39c6871 100644 (file)
 #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,
 };
 
@@ -182,13 +174,13 @@ static ssize_t get_fan_div(struct device *dev, char *buf, int nr)
        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)
+static ssize_t get_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)
+static ssize_t get_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]));
@@ -256,7 +248,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
        return count;
 }
 
-static ssize_t set_fan_pwm(struct device *dev, const char *buf,
+static ssize_t set_pwm(struct device *dev, const char *buf,
                size_t count, int nr)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -275,7 +267,7 @@ static ssize_t set_fan_pwm(struct device *dev, const char *buf,
        return count;
 }
 
-static ssize_t set_fan_pwm_en(struct device *dev, const char *buf,
+static ssize_t set_pwm_en(struct device *dev, const char *buf,
                size_t count, int nr)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -298,43 +290,43 @@ static ssize_t set_fan_pwm_en(struct device *dev, const char *buf,
 #define fan_present(offset)                                            \
 static ssize_t get_fan##offset (struct device *dev, char *buf)         \
 {                                                                      \
-       return get_fan(dev, buf, 0x##offset - 1);                       \
+       return get_fan(dev, buf, offset - 1);                           \
 }                                                                      \
 static ssize_t get_fan##offset##_min (struct device *dev, char *buf)   \
 {                                                                      \
-       return get_fan_min(dev, buf, 0x##offset - 1);                   \
+       return get_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, 0x##offset - 1);            \
+       return set_fan_min(dev, buf, count, offset - 1);                \
 }                                                                      \
 static ssize_t get_fan##offset##_div (struct device *dev, char *buf)   \
 {                                                                      \
-       return get_fan_div(dev, buf, 0x##offset - 1);                   \
+       return get_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, 0x##offset - 1);            \
+       return set_fan_div(dev, buf, count, offset - 1);                \
 }                                                                      \
-static ssize_t get_fan##offset##_pwm (struct device *dev, char *buf)   \
+static ssize_t get_pwm##offset (struct device *dev, char *buf)         \
 {                                                                      \
-       return get_fan_pwm(dev, buf, 0x##offset - 1);                   \
+       return get_pwm(dev, buf, offset - 1);                           \
 }                                                                      \
-static ssize_t set_fan##offset##_pwm (struct device *dev,              \
+static ssize_t set_pwm##offset (struct device *dev,                    \
                const char *buf, size_t count)                          \
 {                                                                      \
-       return set_fan_pwm(dev, buf, count, 0x##offset - 1);            \
+       return set_pwm(dev, buf, count, offset - 1);                    \
 }                                                                      \
-static ssize_t get_fan##offset##_pwm_en (struct device *dev, char *buf)        \
+static ssize_t get_pwm##offset##_en (struct device *dev, char *buf)    \
 {                                                                      \
-       return get_fan_pwm_en(dev, buf, 0x##offset - 1);                \
+       return get_pwm_en(dev, buf, offset - 1);                        \
 }                                                                      \
-static ssize_t set_fan##offset##_pwm_en (struct device *dev,           \
+static ssize_t set_pwm##offset##_en (struct device *dev,               \
                const char *buf, size_t count)                          \
 {                                                                      \
-       return set_fan_pwm_en(dev, buf, count, 0x##offset - 1);         \
+       return set_pwm_en(dev, buf, count, offset - 1);                 \
 }                                                                      \
 static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset,      \
                NULL);                                                  \
@@ -342,10 +334,10 @@ 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);
+static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,                     \
+               get_pwm##offset, set_pwm##offset);                      \
+static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,            \
+               get_pwm##offset##_en, set_pwm##offset##_en);
 
 fan_present(1);
 fan_present(2);
@@ -402,6 +394,7 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
        struct i2c_client *new_client;
        struct smsc47m1_data *data;
        int err = 0;
+       int fan1, fan2, pwm1, pwm2;
 
        if (!i2c_is_isa_adapter(adapter)) {
                return 0;
@@ -431,6 +424,22 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
        new_client->id = smsc47m1_id++;
        init_MUTEX(&data->update_lock);
 
+       /* If no function is properly configured, there's no point in
+          actually registering the chip. */
+       fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05)
+              == 0x05;
+       fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05)
+              == 0x05;
+       pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05)
+              == 0x04;
+       pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
+              == 0x04;
+       if (!(fan1 || fan2 || pwm1 || pwm2)) {
+               dev_warn(&new_client->dev, "Device is not configured, will not use\n");
+               err = -ENODEV;
+               goto error_free;
+       }
+
        if ((err = i2c_attach_client(new_client)))
                goto error_free;
 
@@ -442,8 +451,7 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
           function. */
        smsc47m1_update_device(&new_client->dev, 1);
 
-       if ((smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05)
-           == 0x05) {
+       if (fan1) {
                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);
@@ -451,8 +459,7 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
                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) {
+       if (fan2) {
                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);
@@ -460,17 +467,15 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
                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);
+       if (pwm1) {
+               device_create_file(&new_client->dev, &dev_attr_pwm1);
+               device_create_file(&new_client->dev, &dev_attr_pwm1_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);
+       if (pwm2) {
+               device_create_file(&new_client->dev, &dev_attr_pwm2);
+               device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
        } else
                dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
                        "skipping\n");
index 70e82f2..44a4a35 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/i2c-sensor.h>
 #include <asm/uaccess.h>
 
+static unsigned short empty[] = {I2C_CLIENT_END};
+static unsigned int empty_isa[] = {I2C_CLIENT_ISA_END};
 
 /* Very inefficient for ISA detects, and won't work for 10-bit addresses! */
 int i2c_detect(struct i2c_adapter *adapter,
@@ -42,11 +44,27 @@ int i2c_detect(struct i2c_adapter *adapter,
        int is_isa = i2c_is_isa_adapter(adapter);
        int adapter_id =
            is_isa ? ANY_I2C_ISA_BUS : i2c_adapter_id(adapter);
+       unsigned short *normal_i2c;
+       unsigned int *normal_isa;
+       unsigned short *probe;
+       unsigned short *ignore;
 
        /* Forget it if we can't probe using SMBUS_QUICK */
        if ((!is_isa) &&
            !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK))
                return -1;
+       
+       /* Use default "empty" list if the adapter doesn't specify any */
+       normal_i2c = probe = ignore = empty;
+       normal_isa = empty_isa;
+       if (address_data->normal_i2c)
+               normal_i2c = address_data->normal_i2c;
+       if (address_data->normal_isa)
+               normal_isa = address_data->normal_isa;
+       if (address_data->probe)
+               probe = address_data->probe;
+       if (address_data->ignore)
+               ignore = address_data->ignore;
 
        for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) {
                if (!is_isa && i2c_check_addr(adapter, addr))
@@ -72,81 +90,46 @@ int i2c_detect(struct i2c_adapter *adapter,
 
                /* 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) &&
+               for (i = 0; !found && (ignore[i] != I2C_CLIENT_END); i += 2) {
+                       if ( ((adapter_id == ignore[i]) ||
+                             ((ignore[i] == ANY_I2C_BUS) &&
                               !is_isa)) &&
-                             (addr == address_data->ignore[i + 1])) {
+                             (addr == 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]) {
+                       for (i = 0; !found && (normal_isa[i] != I2C_CLIENT_ISA_END); i += 1) {
+                               if (addr == 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);
+                       for (i = 0; !found && (normal_i2c[i] != I2C_CLIENT_END); i += 1) {
+                               if (addr == normal_i2c[i]) {
                                        found = 1;
+                                       dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x\n", adapter_id, addr);
                                }
                        }
                }
 
                for (i = 0;
-                    !found && (address_data->probe[i] != I2C_CLIENT_END);
+                    !found && (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])) {
+                       if (((adapter_id == probe[i]) ||
+                            ((probe[i] == ANY_I2C_BUS) && !is_isa))
+                           && (addr == 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;
 
index edc9de7..a90f41e 100644 (file)
@@ -1,7 +1,9 @@
 /*
  * linux/drivers/ide/arm/icside.c
  *
- * Copyright (c) 1996-2003 Russell King.
+ * Copyright (c) 1996-2004 Russell King.
+ *
+ * Please note that this platform does not support 32-bit IDE IO.
  */
 
 #include <linux/config.h>
@@ -16,6 +18,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/scatterlist.h>
 
 #include <asm/dma.h>
 #include <asm/ecard.h>
 
 #define ICS_IDENT_OFFSET               0x2280
 
-#define ICS_ARCIN_V5_INTRSTAT          0x000
-#define ICS_ARCIN_V5_INTROFFSET                0x001
-#define ICS_ARCIN_V5_IDEOFFSET         0xa00
-#define ICS_ARCIN_V5_IDEALTOFFSET      0xae0
-#define ICS_ARCIN_V5_IDESTEPPING       4
-
-#define ICS_ARCIN_V6_IDEOFFSET_1       0x800
-#define ICS_ARCIN_V6_INTROFFSET_1      0x880
-#define ICS_ARCIN_V6_INTRSTAT_1                0x8a4
-#define ICS_ARCIN_V6_IDEALTOFFSET_1    0x8e0
-#define ICS_ARCIN_V6_IDEOFFSET_2       0xc00
-#define ICS_ARCIN_V6_INTROFFSET_2      0xc80
-#define ICS_ARCIN_V6_INTRSTAT_2                0xca4
-#define ICS_ARCIN_V6_IDEALTOFFSET_2    0xce0
-#define ICS_ARCIN_V6_IDESTEPPING       4
+#define ICS_ARCIN_V5_INTRSTAT          0x0000
+#define ICS_ARCIN_V5_INTROFFSET                0x0004
+#define ICS_ARCIN_V5_IDEOFFSET         0x2800
+#define ICS_ARCIN_V5_IDEALTOFFSET      0x2b80
+#define ICS_ARCIN_V5_IDESTEPPING       6
+
+#define ICS_ARCIN_V6_IDEOFFSET_1       0x2000
+#define ICS_ARCIN_V6_INTROFFSET_1      0x2200
+#define ICS_ARCIN_V6_INTRSTAT_1                0x2290
+#define ICS_ARCIN_V6_IDEALTOFFSET_1    0x2380
+#define ICS_ARCIN_V6_IDEOFFSET_2       0x3000
+#define ICS_ARCIN_V6_INTROFFSET_2      0x3200
+#define ICS_ARCIN_V6_INTRSTAT_2                0x3290
+#define ICS_ARCIN_V6_IDEALTOFFSET_2    0x3380
+#define ICS_ARCIN_V6_IDESTEPPING       6
 
 struct cardinfo {
        unsigned int dataoffset;
@@ -46,28 +49,28 @@ struct cardinfo {
 };
 
 static struct cardinfo icside_cardinfo_v5 = {
-       ICS_ARCIN_V5_IDEOFFSET,
-       ICS_ARCIN_V5_IDEALTOFFSET,
-       ICS_ARCIN_V5_IDESTEPPING
+       .dataoffset     = ICS_ARCIN_V5_IDEOFFSET,
+       .ctrloffset     = ICS_ARCIN_V5_IDEALTOFFSET,
+       .stepping       = ICS_ARCIN_V5_IDESTEPPING,
 };
 
 static struct cardinfo icside_cardinfo_v6_1 = {
-       ICS_ARCIN_V6_IDEOFFSET_1,
-       ICS_ARCIN_V6_IDEALTOFFSET_1,
-       ICS_ARCIN_V6_IDESTEPPING
+       .dataoffset     = ICS_ARCIN_V6_IDEOFFSET_1,
+       .ctrloffset     = ICS_ARCIN_V6_IDEALTOFFSET_1,
+       .stepping       = ICS_ARCIN_V6_IDESTEPPING,
 };
 
 static struct cardinfo icside_cardinfo_v6_2 = {
-       ICS_ARCIN_V6_IDEOFFSET_2,
-       ICS_ARCIN_V6_IDEALTOFFSET_2,
-       ICS_ARCIN_V6_IDESTEPPING
+       .dataoffset     = ICS_ARCIN_V6_IDEOFFSET_2,
+       .ctrloffset     = ICS_ARCIN_V6_IDEALTOFFSET_2,
+       .stepping       = ICS_ARCIN_V6_IDESTEPPING,
 };
 
 struct icside_state {
        unsigned int channel;
        unsigned int enabled;
-       unsigned long irq_port;
-       unsigned long slot_port;
+       void __iomem *irq_port;
+       void __iomem *ioc_base;
        unsigned int type;
        /* parent device... until the IDE core gets one of its own */
        struct device *dev;
@@ -87,9 +90,8 @@ struct icside_state {
 static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
 {
        struct icside_state *state = ec->irq_data;
-       unsigned int base = state->irq_port;
 
-       outb(0, base + ICS_ARCIN_V5_INTROFFSET);
+       writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
 }
 
 /* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
@@ -98,9 +100,8 @@ static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
 static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
 {
        struct icside_state *state = ec->irq_data;
-       unsigned int base = state->irq_port;
 
-       inb(base + ICS_ARCIN_V5_INTROFFSET);
+       readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
 }
 
 static const expansioncard_ops_t icside_ops_arcin_v5 = {
@@ -116,18 +117,18 @@ static const expansioncard_ops_t icside_ops_arcin_v5 = {
 static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
 {
        struct icside_state *state = ec->irq_data;
-       unsigned int base = state->irq_port;
+       void __iomem *base = state->irq_port;
 
        state->enabled = 1;
 
        switch (state->channel) {
        case 0:
-               outb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
-               inb(base + ICS_ARCIN_V6_INTROFFSET_2);
+               writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
+               readb(base + ICS_ARCIN_V6_INTROFFSET_2);
                break;
        case 1:
-               outb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
-               inb(base + ICS_ARCIN_V6_INTROFFSET_1);
+               writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
+               readb(base + ICS_ARCIN_V6_INTROFFSET_1);
                break;
        }
 }
@@ -141,8 +142,8 @@ static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
 
        state->enabled = 0;
 
-       inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-       inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
 }
 
 /* Prototype: icside_irqprobe(struct expansion_card *ec)
@@ -152,8 +153,8 @@ static int icside_irqpending_arcin_v6(struct expansion_card *ec)
 {
        struct icside_state *state = ec->irq_data;
 
-       return inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
-              inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+       return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+              readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
 }
 
 static const expansioncard_ops_t icside_ops_arcin_v6 = {
@@ -179,23 +180,28 @@ static void icside_maskproc(ide_drive_t *drive, int mask)
        if (state->enabled && !mask) {
                switch (hwif->channel) {
                case 0:
-                       outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-                       inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+                       writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+                       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
                        break;
                case 1:
-                       outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-                       inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+                       writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+                       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
                        break;
                }
        } else {
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+               readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+               readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
        }
 
        local_irq_restore(flags);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+
+#ifndef CONFIG_IDEDMA_ICS_AUTO
+#warning CONFIG_IDEDMA_ICS_AUTO=n support is obsolete, and will be removed soon.
+#endif
+
 /*
  * SG-DMA support.
  *
@@ -205,44 +211,24 @@ static void icside_maskproc(ide_drive_t *drive, int mask)
  * here, but we rely on the main IDE driver spotting that both
  * interfaces use the same IRQ, which should guarantee this.
  */
-#define NR_ENTRIES 256
-#define TABLE_SIZE (NR_ENTRIES * 8)
 
 static void icside_build_sglist(ide_drive_t *drive, struct request *rq)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct icside_state *state = hwif->hwif_data;
        struct scatterlist *sg = hwif->sg_table;
-       int nents;
 
-       if (rq->flags & REQ_DRIVE_TASKFILE) {
-               ide_task_t *args = rq->special;
+       ide_map_sg(drive, rq);
 
-               if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-                       hwif->sg_dma_direction = DMA_TO_DEVICE;
-               else
-                       hwif->sg_dma_direction = DMA_FROM_DEVICE;
-
-               memset(sg, 0, sizeof(*sg));
-               sg->page   = virt_to_page(rq->buffer);
-               sg->offset = offset_in_page(rq->buffer);
-               sg->length = rq->nr_sectors * SECTOR_SIZE;
-               nents = 1;
-       } else {
-               nents = blk_rq_map_sg(drive->queue, rq, sg);
-
-               if (rq_data_dir(rq) == READ)
-                       hwif->sg_dma_direction = DMA_FROM_DEVICE;
-               else
-                       hwif->sg_dma_direction = DMA_TO_DEVICE;
-       }
-
-       nents = dma_map_sg(state->dev, sg, nents, hwif->sg_dma_direction);
+       if (rq_data_dir(rq) == READ)
+               hwif->sg_dma_direction = DMA_FROM_DEVICE;
+       else
+               hwif->sg_dma_direction = DMA_TO_DEVICE;
 
-       hwif->sg_nents = nents;
+       hwif->sg_nents = dma_map_sg(state->dev, sg, hwif->sg_nents,
+                                   hwif->sg_dma_direction);
 }
 
-
 /*
  * Configure the IOMD to give the appropriate timings for the transfer
  * mode being requested.  We take the advice of the ATA standards, and
@@ -402,14 +388,13 @@ static int icside_dma_end(ide_drive_t *drive)
        return get_dma_residue(hwif->hw.dma) != 0;
 }
 
-static int icside_dma_begin(ide_drive_t *drive)
+static void icside_dma_start(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
 
        /* We can not enable DMA on both channels simultaneously. */
        BUG_ON(dma_channel_active(hwif->hw.dma));
        enable_dma(hwif->hw.dma);
-       return 0;
 }
 
 /*
@@ -441,11 +426,16 @@ static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
        return DRIVER(drive)->error(drive, __FUNCTION__, stat);
 }
 
-static int
-icside_dma_common(ide_drive_t *drive, struct request *rq,
-                 unsigned int dma_mode)
+static int icside_dma_setup(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
+       struct request *rq = hwif->hwgroup->rq;
+       unsigned int dma_mode;
+
+       if (rq_data_dir(rq))
+               dma_mode = DMA_MODE_WRITE;
+       else
+               dma_mode = DMA_MODE_READ;
 
        /*
         * We can not enable DMA on both channels.
@@ -462,7 +452,7 @@ icside_dma_common(ide_drive_t *drive, struct request *rq,
        /*
         * Route the DMA signals to the correct interface.
         */
-       outb(hwif->select_data, hwif->config_data);
+       writeb(hwif->select_data, hwif->config_data);
 
        /*
         * Select the correct timing for this drive.
@@ -481,79 +471,10 @@ icside_dma_common(ide_drive_t *drive, struct request *rq,
        return 0;
 }
 
-static int icside_dma_read(ide_drive_t *drive)
+static void icside_dma_exec_cmd(ide_drive_t *drive, u8 cmd)
 {
-       struct request *rq = HWGROUP(drive)->rq;
-       task_ioreg_t cmd;
-
-       if (icside_dma_common(drive, rq, DMA_MODE_READ))
-               return 1;
-
-       if (drive->media != ide_disk)
-               return 0;
-
-       BUG_ON(HWGROUP(drive)->handler != NULL);
-
-       /*
-        * FIX ME to use only ACB ide_task_t args Struct
-        */
-#if 0
-       {
-               ide_task_t *args = rq->special;
-               cmd = args->tfRegister[IDE_COMMAND_OFFSET];
-       }
-#else
-       if (rq->flags & REQ_DRIVE_TASKFILE) {
-               ide_task_t *args = rq->special;
-               cmd = args->tfRegister[IDE_COMMAND_OFFSET];
-       } else if (drive->addressing == 1) {
-               cmd = WIN_READDMA_EXT;
-       } else {
-               cmd = WIN_READDMA;
-       }
-#endif
        /* issue cmd to drive */
        ide_execute_command(drive, cmd, icside_dmaintr, 2*WAIT_CMD, NULL);
-
-       return icside_dma_begin(drive);
-}
-
-static int icside_dma_write(ide_drive_t *drive)
-{
-       struct request *rq = HWGROUP(drive)->rq;
-       task_ioreg_t cmd;
-
-       if (icside_dma_common(drive, rq, DMA_MODE_WRITE))
-               return 1;
-
-       if (drive->media != ide_disk)
-               return 0;
-
-       BUG_ON(HWGROUP(drive)->handler != NULL);
-
-       /*
-        * FIX ME to use only ACB ide_task_t args Struct
-        */
-#if 0
-       {
-               ide_task_t *args = rq->special;
-               cmd = args->tfRegister[IDE_COMMAND_OFFSET];
-       }
-#else
-       if (rq->flags & REQ_DRIVE_TASKFILE) {
-               ide_task_t *args = rq->special;
-               cmd = args->tfRegister[IDE_COMMAND_OFFSET];
-       } else if (drive->addressing == 1) {
-               cmd = WIN_WRITEDMA_EXT;
-       } else {
-               cmd = WIN_WRITEDMA;
-       }
-#endif
-
-       /* issue cmd to drive */
-       ide_execute_command(drive, cmd, icside_dmaintr, 2*WAIT_CMD, NULL);
-
-       return icside_dma_begin(drive);
 }
 
 static int icside_dma_test_irq(ide_drive_t *drive)
@@ -561,20 +482,12 @@ static int icside_dma_test_irq(ide_drive_t *drive)
        ide_hwif_t *hwif = HWIF(drive);
        struct icside_state *state = hwif->hwif_data;
 
-       return inb(state->irq_port +
-                  (hwif->channel ?
+       return readb(state->irq_port +
+                    (hwif->channel ?
                        ICS_ARCIN_V6_INTRSTAT_2 :
                        ICS_ARCIN_V6_INTRSTAT_1)) & 1;
 }
 
-static int icside_dma_verbose(ide_drive_t *drive)
-{
-       printk(", %s (peak %dMB/s)",
-               ide_xfer_verbose(drive->current_speed),
-               2000 / drive->drive_data);
-       return 1;
-}
-
 static int icside_dma_timeout(ide_drive_t *drive)
 {
        printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
@@ -594,7 +507,7 @@ static int icside_dma_lostirq(ide_drive_t *drive)
        return 1;
 }
 
-static int icside_dma_init(ide_hwif_t *hwif)
+static void icside_dma_init(ide_hwif_t *hwif)
 {
        int autodma = 0;
 
@@ -604,11 +517,6 @@ static int icside_dma_init(ide_hwif_t *hwif)
 
        printk("    %s: SG-DMA", hwif->name);
 
-       hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
-                                GFP_KERNEL);
-       if (!hwif->sg_table)
-               goto failed;
-
        hwif->atapi_dma         = 1;
        hwif->mwdma_mask        = 7; /* MW0..2 */
        hwif->swdma_mask        = 7; /* SW0..2 */
@@ -623,12 +531,11 @@ static int icside_dma_init(ide_hwif_t *hwif)
        hwif->ide_dma_off_quietly = icside_dma_off_quietly;
        hwif->ide_dma_host_on   = icside_dma_host_on;
        hwif->ide_dma_on        = icside_dma_on;
-       hwif->ide_dma_read      = icside_dma_read;
-       hwif->ide_dma_write     = icside_dma_write;
-       hwif->ide_dma_begin     = icside_dma_begin;
+       hwif->dma_setup         = icside_dma_setup;
+       hwif->dma_exec_cmd      = icside_dma_exec_cmd;
+       hwif->dma_start         = icside_dma_start;
        hwif->ide_dma_end       = icside_dma_end;
        hwif->ide_dma_test_irq  = icside_dma_test_irq;
-       hwif->ide_dma_verbose   = icside_dma_verbose;
        hwif->ide_dma_timeout   = icside_dma_timeout;
        hwif->ide_dma_lostirq   = icside_dma_lostirq;
 
@@ -636,24 +543,9 @@ static int icside_dma_init(ide_hwif_t *hwif)
        hwif->drives[1].autodma = hwif->autodma;
 
        printk(" capable%s\n", hwif->autodma ? ", auto-enable" : "");
-
-       return 1;
-
-failed:
-       printk(" disabled, unable to allocate DMA table\n");
-       return 0;
-}
-
-static void icside_dma_exit(ide_hwif_t *hwif)
-{
-       if (hwif->sg_table) {
-               kfree(hwif->sg_table);
-               hwif->sg_table = NULL;
-       }
 }
 #else
 #define icside_dma_init(hwif)  (0)
-#define icside_dma_exit(hwif)  do { } while (0)
 #endif
 
 static ide_hwif_t *icside_find_hwif(unsigned long dataport)
@@ -679,24 +571,30 @@ found:
 }
 
 static ide_hwif_t *
-icside_setup(unsigned long base, struct cardinfo *info, struct expansion_card *ec)
+icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *ec)
 {
-       unsigned long port = base + info->dataoffset;
+       unsigned long port = (unsigned long)base + info->dataoffset;
        ide_hwif_t *hwif;
 
-       hwif = icside_find_hwif(base);
+       hwif = icside_find_hwif(port);
        if (hwif) {
                int i;
 
                memset(&hwif->hw, 0, sizeof(hw_regs_t));
 
+               /*
+                * Ensure we're using MMIO
+                */
+               default_hwif_mmiops(hwif);
+               hwif->mmio = 2;
+
                for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
                        hwif->hw.io_ports[i] = port;
                        hwif->io_ports[i] = port;
                        port += 1 << info->stepping;
                }
-               hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-               hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+               hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)base + info->ctrloffset;
+               hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)base + info->ctrloffset;
                hwif->hw.irq  = ec->irq;
                hwif->irq     = ec->irq;
                hwif->noprobe = 0;
@@ -710,14 +608,17 @@ icside_setup(unsigned long base, struct cardinfo *info, struct expansion_card *e
 static int __init
 icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 {
-       unsigned long slot_port;
        ide_hwif_t *hwif;
+       void __iomem *base;
 
-       slot_port = ecard_address(ec, ECARD_MEMC, 0);
+       base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+                      ecard_resource_len(ec, ECARD_RES_MEMC));
+       if (!base)
+               return -ENOMEM;
 
-       state->irq_port = slot_port;
+       state->irq_port = base;
 
-       ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
+       ec->irqaddr  = base + ICS_ARCIN_V5_INTRSTAT;
        ec->irqmask  = 1;
        ec->irq_data = state;
        ec->ops      = &icside_ops_arcin_v5;
@@ -725,61 +626,86 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
        /*
         * Be on the safe side - disable interrupts
         */
-       inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+       icside_irqdisable_arcin_v5(ec, 0);
 
-       hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec);
+       hwif = icside_setup(base, &icside_cardinfo_v5, ec);
+       if (!hwif) {
+               iounmap(base);
+               return -ENODEV;
+       }
 
        state->hwif[0] = hwif;
 
-       return hwif ? 0 : -ENODEV;
+       probe_hwif_init(hwif);
+       create_proc_ide_interfaces();
+
+       return 0;
 }
 
 static int __init
 icside_register_v6(struct icside_state *state, struct expansion_card *ec)
 {
-       unsigned long slot_port, port;
        ide_hwif_t *hwif, *mate;
+       void __iomem *ioc_base, *easi_base;
        unsigned int sel = 0;
+       int ret;
 
-       slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
-       port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
+       ioc_base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+                          ecard_resource_len(ec, ECARD_RES_IOCFAST));
+       if (!ioc_base) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
-       if (port == 0)
-               port = slot_port;
-       else
+       easi_base = ioc_base;
+
+       if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
+               easi_base = ioremap(ecard_resource_start(ec, ECARD_RES_EASI),
+                                   ecard_resource_len(ec, ECARD_RES_EASI));
+               if (!easi_base) {
+                       ret = -ENOMEM;
+                       goto unmap_slot;
+               }
+
+               /*
+                * Enable access to the EASI region.
+                */
                sel = 1 << 5;
+       }
+
+       writeb(sel, ioc_base);
 
-       outb(sel, slot_port);
+       ec->irq_data      = state;
+       ec->ops           = &icside_ops_arcin_v6;
+
+       state->irq_port   = easi_base;
+       state->ioc_base   = ioc_base;
 
        /*
         * Be on the safe side - disable interrupts
         */
-       inb(port + ICS_ARCIN_V6_INTROFFSET_1);
-       inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+       icside_irqdisable_arcin_v6(ec, 0);
 
        /*
         * Find and register the interfaces.
         */
-       hwif = icside_setup(port, &icside_cardinfo_v6_1, ec);
-       mate = icside_setup(port, &icside_cardinfo_v6_2, ec);
+       hwif = icside_setup(easi_base, &icside_cardinfo_v6_1, ec);
+       mate = icside_setup(easi_base, &icside_cardinfo_v6_2, ec);
 
-       if (!hwif || !mate)
-               return -ENODEV;
+       if (!hwif || !mate) {
+               ret = -ENODEV;
+               goto unmap_port;
+       }
 
-       state->irq_port   = port;
-       state->slot_port  = slot_port;
        state->hwif[0]    = hwif;
        state->hwif[1]    = mate;
 
-       ec->irq_data      = state;
-       ec->ops           = &icside_ops_arcin_v6;
-
        hwif->maskproc    = icside_maskproc;
        hwif->channel     = 0;
        hwif->hwif_data   = state;
        hwif->mate        = mate;
        hwif->serialized  = 1;
-       hwif->config_data = slot_port;
+       hwif->config_data = (unsigned long)ioc_base;
        hwif->select_data = sel;
        hwif->hw.dma      = ec->dma;
 
@@ -788,7 +714,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
        mate->hwif_data   = state;
        mate->mate        = hwif;
        mate->serialized  = 1;
-       mate->config_data = slot_port;
+       mate->config_data = (unsigned long)ioc_base;
        mate->select_data = sel | 1;
        mate->hw.dma      = ec->dma;
 
@@ -797,7 +723,19 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
                icside_dma_init(mate);
        }
 
+       probe_hwif_init(hwif);
+       probe_hwif_init(mate);
+       create_proc_ide_interfaces();
+
        return 0;
+
+ unmap_port:
+       if (easi_base != ioc_base)
+               iounmap(easi_base);
+ unmap_slot:
+       iounmap(ioc_base);
+ out:
+       return ret;
 }
 
 static int __devinit
@@ -807,10 +745,14 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
        void *idmem;
        int ret;
 
+       ret = ecard_request_resources(ec);
+       if (ret)
+               goto out;
+
        state = kmalloc(sizeof(struct icside_state), GFP_KERNEL);
        if (!state) {
                ret = -ENOMEM;
-               goto out;
+               goto release;
        }
 
        memset(state, 0, sizeof(state));
@@ -833,12 +775,12 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
 
        switch (state->type) {
        case ICS_TYPE_A3IN:
-               printk(KERN_WARNING "icside: A3IN unsupported\n");
+               dev_warn(&ec->dev, "A3IN unsupported\n");
                ret = -ENODEV;
                break;
 
        case ICS_TYPE_A3USER:
-               printk(KERN_WARNING "icside: A3USER unsupported\n");
+               dev_warn(&ec->dev, "A3USER unsupported\n");
                ret = -ENODEV;
                break;
 
@@ -851,15 +793,19 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
                break;
 
        default:
-               printk(KERN_WARNING "icside: unknown interface type\n");
+               dev_warn(&ec->dev, "unknown interface type\n");
                ret = -ENODEV;
                break;
        }
 
-       if (ret == 0)
+       if (ret == 0) {
                ecard_set_drvdata(ec, state);
-       else
-               kfree(state);
+               goto out;
+       }
+
+       kfree(state);
+ release:
+       ecard_release_resources(ec);
  out:
        return ret;
 }
@@ -873,23 +819,19 @@ static void __devexit icside_remove(struct expansion_card *ec)
                /* FIXME: tell IDE to stop using the interface */
 
                /* Disable interrupts */
-               inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET);
+               icside_irqdisable_arcin_v5(ec, 0);
                break;
 
        case ICS_TYPE_V6:
                /* FIXME: tell IDE to stop using the interface */
-               icside_dma_exit(state->hwif[1]);
-               icside_dma_exit(state->hwif[0]);
-
                if (ec->dma != NO_DMA)
                        free_dma(ec->dma);
 
                /* Disable interrupts */
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+               icside_irqdisable_arcin_v6(ec, 0);
 
                /* Reset the ROM pointer/EASI selection */
-               outb(0, state->slot_port);
+               writeb(0, state->ioc_base);
                break;
        }
 
@@ -897,28 +839,36 @@ static void __devexit icside_remove(struct expansion_card *ec)
        ec->ops = NULL;
        ec->irq_data = NULL;
 
+       if (state->ioc_base)
+               iounmap(state->ioc_base);
+       if (state->ioc_base != state->irq_port)
+               iounmap(state->irq_port);
+
        kfree(state);
+       ecard_release_resources(ec);
 }
 
 static void icside_shutdown(struct expansion_card *ec)
 {
        struct icside_state *state = ecard_get_drvdata(ec);
+       unsigned long flags;
 
-       switch (state->type) {
-       case ICS_TYPE_V5:
-               /* Disable interrupts */
-               inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET);
-               break;
-
-       case ICS_TYPE_V6:
-               /* Disable interrupts */
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-               inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+       /*
+        * Disable interrupts from this card.  We need to do
+        * this before disabling EASI since we may be accessing
+        * this register via that region.
+        */
+       local_irq_save(flags);
+       ec->ops->irqdisable(ec, 0);
+       local_irq_restore(flags);
 
-               /* Reset the ROM pointer/EASI selection */
-               outb(0, state->slot_port);
-               break;
-       }
+       /*
+        * Reset the ROM pointer so that we can read the ROM
+        * after a soft reboot.  This also disables access to
+        * the IDE taskfile via the EASI region.
+        */
+       if (state->ioc_base)
+               writeb(0, state->ioc_base);
 }
 
 static const struct ecard_id icside_ids[] = {
index 2269c28..b0a115d 100644 (file)
 
 #include <asm/ecard.h>
 
-static int __devinit
-rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
+/*
+ * Something like this really should be in generic code, but isn't.
+ */
+static ide_hwif_t *
+rapide_locate_hwif(void __iomem *base, void *ctrl, unsigned int sz, int irq)
 {
-       unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
-       hw_regs_t hw;
-       int i, ret;
+       unsigned long port = (unsigned long)base;
+       ide_hwif_t *hwif;
+       int index, i;
+
+       for (index = 0; index < MAX_HWIFS; ++index) {
+               hwif = ide_hwifs + index;
+               if (hwif->io_ports[IDE_DATA_OFFSET] == port)
+                       goto found;
+       }
+
+       for (index = 0; index < MAX_HWIFS; ++index) {
+               hwif = ide_hwifs + index;
+               if (hwif->io_ports[IDE_DATA_OFFSET] == 0)
+                       goto found;
+       }
 
-       memset(&hw, 0, sizeof(hw));
+       return NULL;
 
+ found:
        for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-               hw.io_ports[i] = port;
-               port += 1 << 4;
+               hwif->hw.io_ports[i] = port;
+               hwif->io_ports[i] = port;
+               port += sz;
        }
-       hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
-       hw.irq = ec->irq;
+       hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+       hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+       hwif->hw.irq = hwif->irq = irq;
+       hwif->mmio = 2;
+       default_hwif_mmiops(hwif);
+
+       return hwif;
+}
 
-       ret = ide_register_hw(&hw, NULL);
+static int __devinit
+rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+       ide_hwif_t *hwif;
+       void __iomem *base;
+       int ret;
 
+       ret = ecard_request_resources(ec);
        if (ret)
-               ecard_release(ec);
+               goto out;
+
+       base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+                      ecard_resource_len(ec, ECARD_RES_MEMC));
+       if (!base) {
+               ret = -ENOMEM;
+               goto release;
+       }
+
+       hwif = rapide_locate_hwif(base, base + 0x818, 1 << 6, ec->irq);
+       if (hwif) {
+               hwif->hwif_data = base;
+               hwif->gendev.parent = &ec->dev;
+               hwif->noprobe = 0;
+               probe_hwif_init(hwif);
+               create_proc_ide_interfaces();
+               ecard_set_drvdata(ec, hwif);
+               goto out;
+       }
+
+       iounmap(base);
+ release:
+       ecard_release_resources(ec);
+ out:
        return ret;
 }
 
 static void __devexit rapide_remove(struct expansion_card *ec)
 {
-       /* need to do more */
+       ide_hwif_t *hwif = ecard_get_drvdata(ec);
+
+       ecard_set_drvdata(ec, NULL);
+
+       /* there must be a better way */
+       ide_unregister(hwif - ide_hwifs);
+       iounmap(hwif->hwif_data);
+       ecard_release_resources(ec);
 }
 
 static struct ecard_id rapide_ids[] = {
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));
+       }
+}
index ef6e2c8..a6bea5d 100644 (file)
 #include <linux/slab.h>
 #include <linux/cdrom.h>
 #include <linux/ide.h>
+#include <linux/bitops.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/unaligned.h>
-#include <asm/bitops.h>
 
 #define IDEDEFAULT_VERSION     "0.9.newide"
 /*
index b2fa5ec..1050de2 100644 (file)
 #include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/bitops.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/bitops.h>
 
 /*
  *     IDE library routines. These are plug in code that most 
@@ -421,8 +421,6 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
                blk_queue_bounce_limit(drive->queue, addr);
 }
 
-EXPORT_SYMBOL(ide_toggle_bounce);
-
 /**
  *     ide_set_xfer_rate       -       set transfer rate
  *     @drive: drive to set
index c0f353e..c797106 100644 (file)
@@ -2,7 +2,6 @@
 obj-$(CONFIG_BLK_DEV_ALI14XX)          += ali14xx.o
 obj-$(CONFIG_BLK_DEV_DTC2278)          += dtc2278.o
 obj-$(CONFIG_BLK_DEV_HT6560B)          += ht6560b.o
-obj-$(CONFIG_BLK_DEV_PDC4030)          += pdc4030.o
 obj-$(CONFIG_BLK_DEV_QD65XX)           += qd65xx.o
 obj-$(CONFIG_BLK_DEV_UMC8672)          += umc8672.o
 
index 537c87c..fb88711 100644 (file)
@@ -226,6 +226,8 @@ static int __init ali14xx_probe(void)
        probe_hwif_init(hwif);
        probe_hwif_init(mate);
 
+       create_proc_ide_interfaces();
+
        return 0;
 }
 
index 65a1e7f..20eb5b8 100644 (file)
@@ -141,6 +141,8 @@ static int __init probe_dtc2278(void)
        probe_hwif_init(hwif);
        probe_hwif_init(mate);
 
+       create_proc_ide_interfaces();
+
        return 0;
 }
 
index eb1c448..a77fb24 100644 (file)
@@ -352,6 +352,8 @@ int __init ht6560b_init(void)
        probe_hwif_init(hwif);
        probe_hwif_init(mate);
 
+       create_proc_ide_interfaces();
+
        return 0;
 
 release_region:
index 2e6267c..563fab0 100644 (file)
@@ -101,7 +101,7 @@ static void qd_write_reg (u8 content, unsigned long reg)
        spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-u8 __init qd_read_reg (unsigned long reg)
+static u8 __init qd_read_reg (unsigned long reg)
 {
        unsigned long flags;
        u8 read;
@@ -429,6 +429,9 @@ static int __init qd_probe(int base)
 
                qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA,
                         &qd6500_tune_drive);
+
+               create_proc_ide_interfaces();
+
                return 1;
        }
 
@@ -459,6 +462,8 @@ static int __init qd_probe(int base)
                                 &qd6580_tune_drive);
                        qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
+                       create_proc_ide_interfaces();
+
                        return 1;
                } else {
                        ide_hwif_t *mate;
@@ -477,6 +482,8 @@ static int __init qd_probe(int base)
                                 &qd6580_tune_drive);
                        qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
+                       create_proc_ide_interfaces();
+
                        return 0; /* no other qd65xx possible */
                }
        }
index 603018e..633a424 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Drive specific timing taken from DOS driver v3.7 */
 
-struct qd65xx_timing_s {
+static struct qd65xx_timing_s {
        s8      offset;   /* ofset from the beginning of Model Number" */
        char    model[4];    /* 4 chars from Model number, no conversion */
        s16     active;   /* active time */
index 68961c2..cdbdb2f 100644 (file)
@@ -161,6 +161,8 @@ static int __init umc8672_probe(void)
        probe_hwif_init(hwif);
        probe_hwif_init(mate);
 
+       create_proc_ide_interfaces();
+
        return 0;
 }
 
index 83bfe92..ec48608 100644 (file)
@@ -183,7 +183,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
 /* 
  * used to set DMA mode for CY82C693 (single and multi modes)
  */
-int cy82c693_ide_dma_on (ide_drive_t *drive)
+static int cy82c693_ide_dma_on (ide_drive_t *drive)
 {
        struct hd_driveid *id = drive->id;
 
index 8eb72f4..59abcf0 100644 (file)
@@ -42,7 +42,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "hpt34x.h"
+#define HPT343_DEBUG_DRIVE_INFO                0
 
 static u8 hpt34x_ratemask (ide_drive_t *drive)
 {
@@ -69,7 +69,8 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
        u8                      hi_speed, lo_speed;
 
-       SPLIT_BYTE(speed, hi_speed, lo_speed);
+       hi_speed = speed >> 4;
+       lo_speed = speed & 0x0f;
 
        if (hi_speed & 7) {
                hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
@@ -130,40 +131,20 @@ static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
        drive->init_speed = 0;
 
        if (id && (id->capability & 1) && drive->autodma) {
-               /* Consult the list of known "bad" drives */
-               if (__ide_dma_bad_drive(drive))
-                       goto fast_ata_pio;
-               if (id->field_valid & 4) {
-                       if (id->dma_ultra & hwif->ultra_mask) {
-                               /* Force if Capable UltraDMA */
-                               int dma = config_chipset_for_dma(drive);
-                               if ((id->field_valid & 2) && dma)
-                                       goto try_dma_modes;
-                       }
-               } else if (id->field_valid & 2) {
-try_dma_modes:
-                       if ((id->dma_mword & hwif->mwdma_mask) ||
-                           (id->dma_1word & hwif->swdma_mask)) {
-                               /* Force if Capable regular DMA modes */
-                               if (!config_chipset_for_dma(drive))
-                                       goto no_dma_set;
-                       }
-               } else if (__ide_dma_good_drive(drive) &&
-                          (id->eide_dma_time < 150)) {
-                       /* Consult the list of known "good" drives */
-                       if (!config_chipset_for_dma(drive))
-                               goto no_dma_set;
-               } else {
-                       goto fast_ata_pio;
-               }
+
+               if (ide_use_dma(drive)) {
+                       if (config_chipset_for_dma(drive))
 #ifndef CONFIG_HPT34X_AUTODMA
-               return hwif->ide_dma_off_quietly(drive);
+                               return hwif->ide_dma_off_quietly(drive);
 #else
-               return hwif->ide_dma_on(drive);
+                               return hwif->ide_dma_on(drive);
 #endif
+               }
+
+               goto fast_ata_pio;
+
        } else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
-no_dma_set:
                hpt34x_tune_drive(drive, 255);
                return hwif->ide_dma_off_quietly(drive);
        }
@@ -249,9 +230,19 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
        hwif->drives[1].autodma = hwif->autodma;
 }
 
+static ide_pci_device_t hpt34x_chipset __devinitdata = {
+       .name           = "HPT34X",
+       .init_chipset   = init_chipset_hpt34x,
+       .init_hwif      = init_hwif_hpt34x,
+       .channels       = 2,
+       .autodma        = NOAUTODMA,
+       .bootable       = NEVER_BOARD,
+       .extra          = 16
+};
+
 static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       ide_pci_device_t *d = &hpt34x_chipsets[id->driver_data];
+       ide_pci_device_t *d = &hpt34x_chipset;
        static char *chipset_names[] = {"HPT343", "HPT345"};
        u16 pcicmd = 0;
 
index 3625e38..011d3f2 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/pci.h>
 #include <linux/adb.h>
 #include <linux/pmu.h>
+#include <linux/scatterlist.h>
 
 #include <asm/prom.h>
 #include <asm/io.h>
@@ -51,8 +52,6 @@
 
 #include "ide-timing.h"
 
-extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
-
 #define IDE_PMAC_DEBUG
 
 #define DMA_WAIT_TIMEOUT       50
@@ -77,10 +76,6 @@ typedef struct pmac_ide_hwif {
         */
        volatile struct dbdma_regs __iomem *    dma_regs;
        struct dbdma_cmd*               dma_table_cpu;
-       dma_addr_t                      dma_table_dma;
-       struct scatterlist*             sg_table;
-       int                             sg_nents;
-       int                             sg_dma_direction;
 #endif
        
 } pmac_ide_hwif_t;
@@ -361,7 +356,6 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed);
 static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio);
 static void pmac_ide_selectproc(ide_drive_t *drive);
 static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
-static int pmac_ide_dma_begin (ide_drive_t *drive);
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
@@ -1245,6 +1239,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
                hwif->noprobe = 0;
 #endif /* CONFIG_PMAC_PBOOK */
 
+       hwif->sg_max_nents = MAX_DCMDS;
+
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
        /* has a DBDMA controller channel */
        if (pmif->dma_regs)
@@ -1364,10 +1360,10 @@ pmac_ide_macio_suspend(struct macio_dev *mdev, u32 state)
        ide_hwif_t      *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
        int             rc = 0;
 
-       if (state != mdev->ofdev.dev.power_state && state >= 2) {
+       if (state != mdev->ofdev.dev.power.power_state && state >= 2) {
                rc = pmac_ide_do_suspend(hwif);
                if (rc == 0)
-                       mdev->ofdev.dev.power_state = state;
+                       mdev->ofdev.dev.power.power_state = state;
        }
 
        return rc;
@@ -1379,10 +1375,10 @@ pmac_ide_macio_resume(struct macio_dev *mdev)
        ide_hwif_t      *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
        int             rc = 0;
        
-       if (mdev->ofdev.dev.power_state != 0) {
+       if (mdev->ofdev.dev.power.power_state != 0) {
                rc = pmac_ide_do_resume(hwif);
                if (rc == 0)
-                       mdev->ofdev.dev.power_state = 0;
+                       mdev->ofdev.dev.power.power_state = 0;
        }
 
        return rc;
@@ -1472,10 +1468,10 @@ pmac_ide_pci_suspend(struct pci_dev *pdev, u32 state)
        ide_hwif_t      *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
        int             rc = 0;
        
-       if (state != pdev->dev.power_state && state >= 2) {
+       if (state != pdev->dev.power.power_state && state >= 2) {
                rc = pmac_ide_do_suspend(hwif);
                if (rc == 0)
-                       pdev->dev.power_state = state;
+                       pdev->dev.power.power_state = state;
        }
 
        return rc;
@@ -1487,10 +1483,10 @@ pmac_ide_pci_resume(struct pci_dev *pdev)
        ide_hwif_t      *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
        int             rc = 0;
        
-       if (pdev->dev.power_state != 0) {
+       if (pdev->dev.power.power_state != 0) {
                rc = pmac_ide_do_resume(hwif);
                if (rc == 0)
-                       pdev->dev.power_state = 0;
+                       pdev->dev.power.power_state = 0;
        }
 
        return rc;
@@ -1561,66 +1557,6 @@ pmac_ide_probe(void)
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
-/*
- * This is very close to the generic ide-dma version of the function except
- * that we don't use the fields in the hwif but our own copies for sg_table
- * and friends. We build & map the sglist for a given request
- */
-static int __pmac
-pmac_ide_build_sglist(ide_drive_t *drive, struct request *rq)
-{
-       ide_hwif_t *hwif = HWIF(drive);
-       pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
-       struct scatterlist *sg = pmif->sg_table;
-       int nents;
-
-       nents = blk_rq_map_sg(drive->queue, rq, sg);
-               
-       if (rq_data_dir(rq) == READ)
-               pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-       else
-               pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-
-       return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
-/*
- * Same as above but for a "raw" taskfile request
- */
-static int __pmac
-pmac_ide_raw_build_sglist(ide_drive_t *drive, struct request *rq)
-{
-       ide_hwif_t *hwif = HWIF(drive);
-       pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
-       struct scatterlist *sg = pmif->sg_table;
-       int nents = 0;
-       ide_task_t *args = rq->special;
-       unsigned char *virt_addr = rq->buffer;
-       int sector_count = rq->nr_sectors;
-
-       if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-               pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-       else
-               pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-       
-       if (sector_count > 128) {
-               memset(&sg[nents], 0, sizeof(*sg));
-               sg[nents].page = virt_to_page(virt_addr);
-               sg[nents].offset = offset_in_page(virt_addr);
-               sg[nents].length = 128  * SECTOR_SIZE;
-               nents++;
-               virt_addr = virt_addr + (128 * SECTOR_SIZE);
-               sector_count -= 128;
-       }
-       memset(&sg[nents], 0, sizeof(*sg));
-       sg[nents].page = virt_to_page(virt_addr);
-       sg[nents].offset = offset_in_page(virt_addr);
-       sg[nents].length =  sector_count  * SECTOR_SIZE;
-       nents++;
-   
-       return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
 /*
  * pmac_ide_build_dmatable builds the DBDMA command list
  * for a transfer and sets the DBDMA channel to point to it.
@@ -1644,16 +1580,13 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
        while (readl(&dma->status) & RUN)
                udelay(1);
 
-       /* Build sglist */
-       if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE)
-               pmif->sg_nents = i = pmac_ide_raw_build_sglist(drive, rq);
-       else
-               pmif->sg_nents = i = pmac_ide_build_sglist(drive, rq);
+       hwif->sg_nents = i = ide_build_sglist(drive, rq);
+
        if (!i)
                return 0;
 
        /* Build DBDMA commands list */
-       sg = pmif->sg_table;
+       sg = hwif->sg_table;
        while (i && sg_dma_len(sg)) {
                u32 cur_addr;
                u32 cur_len;
@@ -1698,16 +1631,16 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
                memset(table, 0, sizeof(struct dbdma_cmd));
                st_le16(&table->command, DBDMA_STOP);
                mb();
-               writel(pmif->dma_table_dma, &dma->cmdptr);
+               writel(hwif->dmatable_dma, &dma->cmdptr);
                return 1;
        }
 
        printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
  use_pio_instead:
        pci_unmap_sg(hwif->pci_dev,
-                    pmif->sg_table,
-                    pmif->sg_nents,
-                    pmif->sg_dma_direction);
+                    hwif->sg_table,
+                    hwif->sg_nents,
+                    hwif->sg_dma_direction);
        return 0; /* revert to PIO for this request */
 }
 
@@ -1715,14 +1648,14 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
 static void __pmac
 pmac_ide_destroy_dmatable (ide_drive_t *drive)
 {
+       ide_hwif_t *hwif = drive->hwif;
        struct pci_dev *dev = HWIF(drive)->pci_dev;
-       pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
-       struct scatterlist *sg = pmif->sg_table;
-       int nents = pmif->sg_nents;
+       struct scatterlist *sg = hwif->sg_table;
+       int nents = hwif->sg_nents;
 
        if (nents) {
-               pci_unmap_sg(dev, sg, nents, pmif->sg_dma_direction);
-               pmif->sg_nents = 0;
+               pci_unmap_sg(dev, sg, nents, hwif->sg_dma_direction);
+               hwif->sg_nents = 0;
        }
 }
 
@@ -1885,7 +1818,7 @@ pmac_ide_dma_check(ide_drive_t *drive)
  * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
  */
 static int __pmac
-pmac_ide_dma_start(ide_drive_t *drive, int reading)
+pmac_ide_dma_setup(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
        pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
@@ -1897,12 +1830,14 @@ pmac_ide_dma_start(ide_drive_t *drive, int reading)
                return 1;
        ata4 = (pmif->kind == controller_kl_ata4);      
 
-       if (!pmac_ide_build_dmatable(drive, rq))
+       if (!pmac_ide_build_dmatable(drive, rq)) {
+               ide_map_sg(drive, rq);
                return 1;
+       }
 
        /* Apple adds 60ns to wrDataSetup on reads */
        if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
-               writel(pmif->timings[unit] + (reading ? 0x00800000UL : 0),
+               writel(pmif->timings[unit] + (!rq_data_dir(rq) ? 0x00800000UL : 0),
                        PMAC_IDE_REG(IDE_TIMING_CONFIG));
                (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
        }
@@ -1912,87 +1847,28 @@ pmac_ide_dma_start(ide_drive_t *drive, int reading)
        return 0;
 }
 
-/*
- * Start a DMA READ command
- */
-static int __pmac
-pmac_ide_dma_read(ide_drive_t *drive)
-{
-       struct request *rq = HWGROUP(drive)->rq;
-       u8 lba48 = (drive->addressing == 1) ? 1 : 0;
-       task_ioreg_t command = WIN_NOP;
-
-       if (pmac_ide_dma_start(drive, 1))
-               return 1;
-
-       if (drive->media != ide_disk)
-               return 0;
-
-       command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
-       
-       if (drive->vdma)
-               command = (lba48) ? WIN_READ_EXT: WIN_READ;
-               
-       if (rq->flags & REQ_DRIVE_TASKFILE) {
-               ide_task_t *args = rq->special;
-               command = args->tfRegister[IDE_COMMAND_OFFSET];
-       }
-
-       /* issue cmd to drive */
-       ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL);
-
-       return pmac_ide_dma_begin(drive);
-}
-
-/*
- * Start a DMA WRITE command
- */
-static int __pmac
-pmac_ide_dma_write (ide_drive_t *drive)
+static void __pmac
+pmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
 {
-       struct request *rq = HWGROUP(drive)->rq;
-       u8 lba48 = (drive->addressing == 1) ? 1 : 0;
-       task_ioreg_t command = WIN_NOP;
-
-       if (pmac_ide_dma_start(drive, 0))
-               return 1;
-
-       if (drive->media != ide_disk)
-               return 0;
-
-       command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
-       if (drive->vdma)
-               command = (lba48) ? WIN_WRITE_EXT: WIN_WRITE;
-               
-       if (rq->flags & REQ_DRIVE_TASKFILE) {
-               ide_task_t *args = rq->special;
-               command = args->tfRegister[IDE_COMMAND_OFFSET];
-       }
-
        /* issue cmd to drive */
        ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL);
-
-       return pmac_ide_dma_begin(drive);
 }
 
 /*
  * Kick the DMA controller into life after the DMA command has been issued
  * to the drive.
  */
-static int __pmac
-pmac_ide_dma_begin (ide_drive_t *drive)
+static void __pmac
+pmac_ide_dma_start(ide_drive_t *drive)
 {
        pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
        volatile struct dbdma_regs __iomem *dma;
 
-       if (pmif == NULL)
-               return 1;
        dma = pmif->dma_regs;
 
        writel((RUN << 16) | RUN, &dma->control);
        /* Make sure it gets to the controller right now */
        (void)readl(&dma->control);
-       return 0;
 }
 
 /*
@@ -2130,42 +2006,26 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
        pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
                hwif->pci_dev,
                (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-               &pmif->dma_table_dma);
+               &hwif->dmatable_dma);
        if (pmif->dma_table_cpu == NULL) {
                printk(KERN_ERR "%s: unable to allocate DMA command list\n",
                       hwif->name);
                return;
        }
 
-       pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
-                                GFP_KERNEL);
-       if (pmif->sg_table == NULL) {
-               pci_free_consistent(    hwif->pci_dev,
-                                       (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-                                       pmif->dma_table_cpu, pmif->dma_table_dma);
-               return;
-       }
        hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
        hwif->ide_dma_on = &__ide_dma_on;
        hwif->ide_dma_check = &pmac_ide_dma_check;
-       hwif->ide_dma_read = &pmac_ide_dma_read;
-       hwif->ide_dma_write = &pmac_ide_dma_write;
-       hwif->ide_dma_begin = &pmac_ide_dma_begin;
+       hwif->dma_setup = &pmac_ide_dma_setup;
+       hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;
+       hwif->dma_start = &pmac_ide_dma_start;
        hwif->ide_dma_end = &pmac_ide_dma_end;
        hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
        hwif->ide_dma_host_off = &pmac_ide_dma_host_off;
        hwif->ide_dma_host_on = &pmac_ide_dma_host_on;
-       hwif->ide_dma_verbose = &__ide_dma_verbose;
        hwif->ide_dma_timeout = &__ide_dma_timeout;
        hwif->ide_dma_lostirq = &pmac_ide_dma_lostirq;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-       if (!noautodma)
-               hwif->autodma = 1;
-#endif
-       hwif->drives[0].autodma = hwif->autodma;
-       hwif->drives[1].autodma = hwif->autodma;
-
        hwif->atapi_dma = 1;
        switch(pmif->kind) {
                case controller_un_ata6:
index afcf7f8..7c3f6e7 100644 (file)
@@ -94,7 +94,6 @@
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/poll.h>
-#include <linux/irq.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
 
 #include <asm/pgtable.h>
 #include <asm/page.h>
+#include <asm/irq.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/vmalloc.h>
@@ -2933,8 +2933,8 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
        d->ctrlClear = 0;
        d->cmdPtr = 0;
 
-       d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
-       d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
+       d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_ATOMIC);
+       d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_ATOMIC);
 
        if (d->buf_cpu == NULL || d->buf_bus == NULL) {
                PRINT(KERN_ERR, "Failed to allocate dma buffer");
@@ -2945,8 +2945,8 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
        memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t));
 
        d->prg_cpu = kmalloc(d->num_desc * sizeof(struct dma_cmd*),
-                            GFP_KERNEL);
-       d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
+                               GFP_ATOMIC);
+       d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_ATOMIC);
 
        if (d->prg_cpu == NULL || d->prg_bus == NULL) {
                PRINT(KERN_ERR, "Failed to allocate dma prg");
@@ -2956,7 +2956,7 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
        memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*));
        memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
 
-       d->spb = kmalloc(d->split_buf_size, GFP_KERNEL);
+       d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC);
 
        if (d->spb == NULL) {
                PRINT(KERN_ERR, "Failed to allocate split buffer");
index 13722da..dc78e21 100644 (file)
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/poll.h>
-#include <linux/irq.h>
 #include <linux/kdev_t.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/irq.h>
 
 #include "csr1212.h"
 #include "ieee1394.h"
index 9c784cc..644ec55 100644 (file)
@@ -49,10 +49,10 @@ struct ti_lynx {
                have_1394_buffers, have_iomappings, is_host } state;
 
         /* remapped memory spaces */
-        void *registers;
-        void *local_rom;
-        void *local_ram;
-        void *aux_port;
+        void __iomem *registers;
+        void __iomem *local_rom;
+        void __iomem *local_ram;
+        void __iomem *aux_port;
        quadlet_t bus_info_block[5];
 
 #ifdef CONFIG_IEEE1394_PCILYNX_PORTS
index d12f8e1..94b59f8 100644 (file)
@@ -52,15 +52,15 @@ struct sbp2_command_orb {
        u8 cdb[12];
 };
 
-#define LOGIN_REQUEST                  0x0
-#define QUERY_LOGINS_REQUEST           0x1
-#define RECONNECT_REQUEST              0x3
-#define SET_PASSWORD_REQUEST           0x4
-#define LOGOUT_REQUEST                 0x7
-#define ABORT_TASK_REQUEST             0xb
-#define ABORT_TASK_SET                 0xc
-#define LOGICAL_UNIT_RESET             0xe
-#define TARGET_RESET_REQUEST           0xf
+#define SBP2_LOGIN_REQUEST             0x0
+#define SBP2_QUERY_LOGINS_REQUEST      0x1
+#define SBP2_RECONNECT_REQUEST         0x3
+#define SBP2_SET_PASSWORD_REQUEST      0x4
+#define SBP2_LOGOUT_REQUEST            0x7
+#define SBP2_ABORT_TASK_REQUEST                0xb
+#define SBP2_ABORT_TASK_SET            0xc
+#define SBP2_LOGICAL_UNIT_RESET                0xe
+#define SBP2_TARGET_RESET_REQUEST      0xf
 
 #define ORB_SET_LUN(value)                      (value & 0xffff)
 #define ORB_SET_FUNCTION(value)                 ((value & 0xf) << 16)
index 93849a6..ab0a151 100644 (file)
@@ -98,8 +98,8 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
        pci_enable_device(pci);
        gp->gameport.io = pci_resource_start(pci, 0);
        if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) {
-               kfree(gp);
                printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f);
+               kfree(gp);
                return -1;
        }
 
index 8b5fc35..cf36ca9 100644 (file)
@@ -46,8 +46,7 @@ MODULE_DESCRIPTION("Driver for Amiga joysticks");
 MODULE_LICENSE("GPL");
 
 static int amijoy[2] = { 0, 1 };
-static int amijoy_nargs;
-module_param_array_named(map, amijoy, uint, amijoy_nargs, 0);
+module_param_array_named(map, amijoy, uint, NULL, 0);
 MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)");
 
 __obsolete_setup("amijoy=");
index 5ad6127..c5c6115 100644 (file)
@@ -45,17 +45,17 @@ MODULE_LICENSE("GPL");
 
 static int db9[] __initdata = { -1, 0 };
 static int db9_nargs __initdata = 0;
-module_param_array_named(dev, db9, int, db9_nargs, 0);
+module_param_array_named(dev, db9, int, &db9_nargs, 0);
 MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)");
 
 static int db9_2[] __initdata = { -1, 0 };
 static int db9_nargs_2 __initdata = 0;
-module_param_array_named(dev2, db9_2, int, db9_nargs_2, 0);
+module_param_array_named(dev2, db9_2, int, &db9_nargs_2, 0);
 MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)");
 
 static int db9_3[] __initdata = { -1, 0 };
 static int db9_nargs_3 __initdata = 0;
-module_param_array_named(dev3, db9_3, int, db9_nargs_3, 0);
+module_param_array_named(dev3, db9_3, int, &db9_nargs_3, 0);
 MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)");
 
 __obsolete_setup("db9=");
index 46326b7..3f2cdb6 100644 (file)
@@ -43,17 +43,17 @@ MODULE_LICENSE("GPL");
 
 static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
 static int gc_nargs __initdata = 0;
-module_param_array_named(map, gc, int, gc_nargs, 0);
+module_param_array_named(map, gc, int, &gc_nargs, 0);
 MODULE_PARM_DESC(map, "Describers first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)");
 
 static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
 static int gc_nargs_2 __initdata = 0;
-module_param_array_named(map2, gc_2, int, gc_nargs_2, 0);
+module_param_array_named(map2, gc_2, int, &gc_nargs_2, 0);
 MODULE_PARM_DESC(map2, "Describers second set of devices");
 
 static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
 static int gc_nargs_3 __initdata = 0;
-module_param_array_named(map3, gc_3, int, gc_nargs_3, 0);
+module_param_array_named(map3, gc_3, int, &gc_nargs_3, 0);
 MODULE_PARM_DESC(map3, "Describers third set of devices");
 
 __obsolete_setup("gc=");
index 123ff5f..0e620cb 100644 (file)
@@ -44,17 +44,17 @@ MODULE_LICENSE("GPL");
 
 static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
 static int tgfx_nargs __initdata = 0;
-module_param_array_named(map, tgfx, int, tgfx_nargs, 0);
+module_param_array_named(map, tgfx, int, &tgfx_nargs, 0);
 MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>");
 
 static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
 static int tgfx_nargs_2 __initdata = 0;
-module_param_array_named(map2, tgfx_2, int, tgfx_nargs_2, 0);
+module_param_array_named(map2, tgfx_2, int, &tgfx_nargs_2, 0);
 MODULE_PARM_DESC(map2, "Describes second set of devices");
 
 static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
 static int tgfx_nargs_3 __initdata = 0;
-module_param_array_named(map3, tgfx_3, int, tgfx_nargs_3, 0);
+module_param_array_named(map3, tgfx_3, int, &tgfx_nargs_3, 0);
 MODULE_PARM_DESC(map3, "Describes third set of devices");
 
 __obsolete_setup("tgfx=");
index fa8cff3..0c74918 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/input.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/pci.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -107,8 +108,22 @@ static int pc110pad_open(struct input_dev *dev)
        return 0;
 }
 
+/*
+ * We try to avoid enabling the hardware if it's not
+ * there, but we don't know how to test. But we do know
+ * that the PC110 is not a PCI system. So if we find any
+ * PCI devices in the machine, we don't have a PC110.
+ */
 static int __init pc110pad_init(void)
 {
+       struct pci_dev *dev;
+
+       dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
+       if (dev) {
+               pci_dev_put(dev);
+               return -ENOENT;
+       }
+
        if (!request_region(pc110pad_io, 4, "pc110pad")) {
                printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n",
                                pc110pad_io, pc110pad_io + 4);
index 7d5ecce..a56ea2b 100644 (file)
@@ -36,8 +36,8 @@
 #include <linux/serio.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/q40_master.h>
index b25d2e3..49a5841 100644 (file)
@@ -45,9 +45,6 @@ MODULE_AUTHOR("Vojtech Pavlik, Russell King");
 MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
 MODULE_LICENSE("GPL");
 
-static struct serio *rpckbd_port;
-static struct platform_device *rpckbd_device;
-
 static int rpckbd_write(struct serio *port, unsigned char val)
 {
        while (!(iomd_readb(IOMD_KCTRL) & (1 << 7)))
@@ -109,45 +106,50 @@ static void rpckbd_close(struct serio *port)
  * Allocate and initialize serio structure for subsequent registration
  * with serio core.
  */
-
-static struct serio * __init rpckbd_allocate_port(void)
+static int __devinit rpckbd_probe(struct device *dev)
 {
        struct serio *serio;
 
        serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
-       if (serio) {
-               memset(serio, 0, sizeof(struct serio));
-               serio->type             = SERIO_8042;
-               serio->write            = rpckbd_write;
-               serio->open             = rpckbd_open;
-               serio->close            = rpckbd_close;
-               serio->dev.parent       = &rpckbd_device->dev;
-               strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name));
-               strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys));
-       }
+       if (!serio)
+               return -ENOMEM;
 
-       return serio;
+       memset(serio, 0, sizeof(struct serio));
+       serio->type             = SERIO_8042;
+       serio->write            = rpckbd_write;
+       serio->open             = rpckbd_open;
+       serio->close            = rpckbd_close;
+       serio->dev.parent       = dev;
+       strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name));
+       strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys));
+
+       dev_set_drvdata(dev, serio);
+       serio_register_port(serio);
+       return 0;
 }
 
-static int __init rpckbd_init(void)
+static int __devexit rpckbd_remove(struct device *dev)
 {
-       rpckbd_device = platform_device_register_simple("rpckbd", -1, NULL, 0);
-       if (IS_ERR(rpckbd_device))
-               return PTR_ERR(rpckbd_device);
+       struct serio *serio = dev_get_drvdata(dev);
+       serio_unregister_port(serio);
+       return 0;
+}
 
-       if (!(rpckbd_port = rpckbd_allocate_port())) {
-               platform_device_unregister(rpckbd_device);
-               return -ENOMEM;
-       }
+static struct device_driver rpckbd_driver = {
+       .name           = "kart",
+       .bus            = &platform_bus_type,
+       .probe          = rpckbd_probe,
+       .remove         = __devexit_p(rpckbd_remove),
+};
 
-       serio_register_port(rpckbd_port);
-       return 0;
+static int __init rpckbd_init(void)
+{
+       return driver_register(&rpckbd_driver);
 }
 
 static void __exit rpckbd_exit(void)
 {
-       serio_unregister_port(rpckbd_port);
-       platform_device_unregister(rpckbd_device);
+       driver_unregister(&rpckbd_driver);
 }
 
 module_init(rpckbd_init);
index 268ca1d..deb6014 100644 (file)
@@ -246,11 +246,6 @@ static ssize_t serio_show_description(struct device *dev, char *buf)
        return sprintf(buf, "%s\n", serio->name);
 }
 
-static ssize_t serio_show_driver(struct device *dev, char *buf)
-{
-       return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)");
-}
-
 static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count)
 {
        struct serio *serio = to_serio_port(dev);
@@ -307,7 +302,7 @@ static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t c
 
 static struct device_attribute serio_device_attrs[] = {
        __ATTR(description, S_IRUGO, serio_show_description, NULL),
-       __ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver),
+       __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver),
        __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
        __ATTR_NULL
 };
index ede2b7e..434e684 100644 (file)
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
+
 #include "isdn_divert.h"
 
 MODULE_DESCRIPTION("ISDN4Linux: Call diversion support");
 MODULE_AUTHOR("Werner Cornelius");
 MODULE_LICENSE("GPL");
 
-/********************/
-/* needed externals */
-/********************/
-extern int printk(const char *fmt,...);
-
 /****************************************/
 /* structure containing interface to hl */
 /****************************************/
@@ -59,23 +56,23 @@ static int __init divert_init(void)
 /* Module deinit code */
 /**********************/
 static void __exit divert_exit(void)
-{ unsigned long flags;
+{
+  unsigned long flags;
   int i;
 
-  save_flags(flags);
-  cli();
+  spin_lock_irqsave(&divert_lock, flags);
   divert_if.cmd = DIVERT_CMD_REL; /* release */
   if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
    { printk(KERN_WARNING "dss1_divert: error %d releasing module\n",i);
-     restore_flags(flags);
+     spin_unlock_irqrestore(&divert_lock, flags);
      return;
    } 
   if (divert_dev_deinit()) 
    { printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
-     restore_flags(flags);
+     spin_unlock_irqrestore(&divert_lock, flags);
      return;
    }
-  restore_flags(flags);
+  spin_unlock_irqrestore(&divert_lock, flags);
   deleterule(-1); /* delete all rules and free mem */
   deleteprocs();
   printk(KERN_INFO "dss1_divert module successfully removed \n");
index d3506ee..9571f03 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/isdnif.h>
 #include "isdn_divert.h"
 
+
 /*********************************/
 /* Variables for interface queue */
 /*********************************/
@@ -76,7 +77,7 @@ put_info_buffer(char *cp)
 /* deflection device read routine */
 /**********************************/
 static ssize_t
-isdn_divert_read(struct file *file, char *buf, size_t count, loff_t * off)
+isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t * off)
 {
        struct divert_info *inf;
        int len;
@@ -90,7 +91,7 @@ isdn_divert_read(struct file *file, char *buf, size_t count, loff_t * off)
                return (0);
 
        inf->usage_cnt--;       /* new usage count */
-       (struct divert_info **) file->private_data = &inf->next;        /* next structure */
+       file->private_data = &inf->next;        /* next structure */
        if ((len = strlen(inf->info_start)) <= count) {
                if (copy_to_user(buf, inf->info_start, len))
                        return -EFAULT;
@@ -104,7 +105,7 @@ isdn_divert_read(struct file *file, char *buf, size_t count, loff_t * off)
 /* deflection device write routine */
 /**********************************/
 static ssize_t
-isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t * off)
+isdn_divert_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
 {
        return (-ENODEV);
 }                              /* isdn_divert_write */
@@ -137,9 +138,9 @@ isdn_divert_open(struct inode *ino, struct file *filep)
        spin_lock_irqsave( &divert_info_lock, flags );
        if_used++;
        if (divert_info_head)
-               (struct divert_info **) filep->private_data = &(divert_info_tail->next);
+               filep->private_data = &(divert_info_tail->next);
        else
-               (struct divert_info **) filep->private_data = &divert_info_head;
+               filep->private_data = &divert_info_head;
        spin_unlock_irqrestore( &divert_info_lock, flags );
        /*  start_divert(); */
        return nonseekable_open(ino, filep);
@@ -184,7 +185,7 @@ isdn_divert_ioctl(struct inode *inode, struct file *file,
        divert_rule *rulep;
        char *cp;
 
-       if (copy_from_user(&dioctl, (char *) arg, sizeof(dioctl)))
+       if (copy_from_user(&dioctl, (void __user *) arg, sizeof(dioctl)))
                return -EFAULT;
 
        switch (cmd) {
@@ -215,10 +216,9 @@ isdn_divert_ioctl(struct inode *inode, struct file *file,
                case IIOCMODRULE:
                        if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
                                return (-EINVAL);
-                       save_flags(flags);
-                       cli();
+            spin_lock_irqsave(&divert_lock, flags);
                        *rulep = dioctl.getsetrule.rule;        /* copy data */
-                       restore_flags(flags);
+                       spin_unlock_irqrestore(&divert_lock, flags);
                        return (0);     /* no copy required */
                        break;
 
@@ -253,7 +253,7 @@ isdn_divert_ioctl(struct inode *inode, struct file *file,
                default:
                        return (-EINVAL);
        }                       /* switch cmd */
-       return copy_to_user((char *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
+       return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
 }                              /* isdn_divert_ioctl */
 
 
index 568530d..89c72c8 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/version.h>
 #include <linux/proc_fs.h>
+
 #include "isdn_divert.h"
 
 /**********************************/
@@ -47,54 +48,53 @@ static struct deflect_struc *table_head = NULL;
 static struct deflect_struc *table_tail = NULL; 
 static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */ 
 
+spinlock_t divert_lock = SPIN_LOCK_UNLOCKED;
+
 /***************************/
 /* timer callback function */
 /***************************/
 static void deflect_timer_expire(ulong arg)
-{ unsigned long flags;
+{
+  unsigned long flags;
   struct call_struc *cs = (struct call_struc *) arg;
 
-  save_flags(flags);
-  cli();
+  spin_lock_irqsave(&divert_lock, flags);
   del_timer(&cs->timer); /* delete active timer */
-  restore_flags(flags);
+  spin_unlock_irqrestore(&divert_lock, flags);
 
   switch(cs->akt_state)
    { case DEFLECT_PROCEED:
        cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
        divert_if.ll_cmd(&cs->ics);                       
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&divert_lock, flags);
        cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
        cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
        add_timer(&cs->timer);
-       restore_flags(flags); 
+       spin_unlock_irqrestore(&divert_lock, flags);
        break;
 
      case DEFLECT_ALERT:
        cs->ics.command = ISDN_CMD_REDIR; /* protocol */
        strcpy(cs->ics.parm.setup.phone,cs->deflect_dest);
        strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed");
-       divert_if.ll_cmd(&cs->ics);                       
-       save_flags(flags);
-       cli();
+       divert_if.ll_cmd(&cs->ics);
+       spin_lock_irqsave(&divert_lock, flags);
        cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
        cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
        add_timer(&cs->timer);
-       restore_flags(flags); 
+       spin_unlock_irqrestore(&divert_lock, flags);
        break;
 
      case DEFLECT_AUTODEL:
      default:
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&divert_lock, flags);
        if (cs->prev) 
          cs->prev->next = cs->next; /* forward link */
         else
          divert_head = cs->next;
        if (cs->next)
          cs->next->prev = cs->prev; /* back link */           
-       restore_flags(flags); 
+       spin_unlock_irqrestore(&divert_lock, flags);
        kfree(cs);
        return;
 
@@ -166,10 +166,9 @@ int cf_command(int drvid, int mode,
   cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
   cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
   
-  save_flags(flags);
-  cli();
+  spin_lock_irqsave(&divert_lock, flags);
   cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
-  restore_flags(flags);
+  spin_unlock_irqrestore(&divert_lock, flags);
   *procid = cs->ics.parm.dss1_io.ll_id;  
 
   sprintf(cs->info,"%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
@@ -187,11 +186,10 @@ int cf_command(int drvid, int mode,
 
   if (!retval)
    { cs->prev = NULL;
-     save_flags(flags);
-     cli();
+     spin_lock_irqsave(&divert_lock, flags);
      cs->next = divert_head;
      divert_head = cs; 
-     restore_flags(flags);
+     spin_unlock_irqrestore(&divert_lock, flags);
    }
   else
    kfree(cs);
@@ -224,13 +222,12 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
    { case 0: /* hangup */
        del_timer(&cs->timer); 
        ic.command = ISDN_CMD_HANGUP;
-       i = divert_if.ll_cmd(&ic);                        
-       save_flags(flags);
-       cli();
+       i = divert_if.ll_cmd(&ic);
+       spin_lock_irqsave(&divert_lock, flags);
        cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
        cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
        add_timer(&cs->timer);
-       restore_flags(flags); 
+       spin_unlock_irqrestore(&divert_lock, flags);
      break;      
 
      case 1: /* alert */
@@ -239,12 +236,12 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
        del_timer(&cs->timer); 
        ic.command = ISDN_CMD_ALERT;
        if ((i = divert_if.ll_cmd(&ic)))
-       { save_flags(flags);
-          cli();
+       {
+          spin_lock_irqsave(&divert_lock, flags);
           cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
           cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
           add_timer(&cs->timer);
-          restore_flags(flags);
+          spin_unlock_irqrestore(&divert_lock, flags);
         }
        else
           cs->akt_state = DEFLECT_ALERT; 
@@ -256,12 +253,12 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
        strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
        ic.command = ISDN_CMD_REDIR;
        if ((i = divert_if.ll_cmd(&ic)))
-       { save_flags(flags);
-          cli();
+       {
+          spin_lock_irqsave(&divert_lock, flags);
           cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
           cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
           add_timer(&cs->timer);
-          restore_flags(flags);
+          spin_unlock_irqrestore(&divert_lock, flags);
         }
        else
           cs->akt_state = DEFLECT_ALERT; 
@@ -284,8 +281,7 @@ int insertrule(int idx, divert_rule *newrule)
 
   ds->rule = *newrule; /* set rule */
 
-  save_flags(flags);
-  cli();
+  spin_lock_irqsave(&divert_lock, flags);
 
   if (idx >= 0)
    { ds1 = table_head;
@@ -313,7 +309,7 @@ int insertrule(int idx, divert_rule *newrule)
         table_head = ds; /* first element */
    }
 
-  restore_flags(flags);
+  spin_unlock_irqrestore(&divert_lock, flags);
   return(0);
 } /* insertrule */
 
@@ -325,12 +321,11 @@ int deleterule(int idx)
   unsigned long flags;
   
   if (idx < 0) 
-   { save_flags(flags);
-     cli();
+   { spin_lock_irqsave(&divert_lock, flags);
      ds = table_head;
      table_head = NULL;
      table_tail = NULL;
-     restore_flags(flags);
+     spin_unlock_irqrestore(&divert_lock, flags);
      while (ds)
       { ds1 = ds; 
         ds = ds->next;
@@ -339,8 +334,7 @@ int deleterule(int idx)
      return(0); 
    }
 
-  save_flags(flags);
-  cli();
+  spin_lock_irqsave(&divert_lock, flags);
   ds = table_head;
 
   while ((ds) && (idx > 0))
@@ -349,7 +343,8 @@ int deleterule(int idx)
    }
 
   if (!ds) 
-   { restore_flags(flags);
+   {
+     spin_unlock_irqrestore(&divert_lock, flags);
      return(-EINVAL);
    }  
 
@@ -363,7 +358,7 @@ int deleterule(int idx)
    else
      table_head = ds->next; /* start of chain */      
   
-  restore_flags(flags);
+  spin_unlock_irqrestore(&divert_lock, flags);
   kfree(ds);
   return(0);
 } /* deleterule */
@@ -474,10 +469,9 @@ int isdn_divert_icall(isdn_ctrl *ic)
             else  
               cs->timer.expires = 0;
            cs->akt_state = dv->rule.action;                
-           save_flags(flags);
-           cli();
+           spin_lock_irqsave(&divert_lock, flags);
            cs->divert_id = next_id++; /* new sequence number */
-           restore_flags(flags);
+           spin_unlock_irqrestore(&divert_lock, flags);
            cs->prev = NULL;
            if (cs->akt_state == DEFLECT_ALERT)
              { strcpy(cs->deflect_dest,dv->rule.to_nr);
@@ -525,12 +519,11 @@ int isdn_divert_icall(isdn_ctrl *ic)
 
   if (cs) 
    { cs->prev = NULL;
-     save_flags(flags);
-     cli();
+     spin_lock_irqsave(&divert_lock, flags);
      cs->next = divert_head;
      divert_head = cs; 
      if (cs->timer.expires) add_timer(&cs->timer);
-     restore_flags(flags);
+     spin_unlock_irqrestore(&divert_lock, flags);
 
      put_info_buffer(cs->info); 
      return(retval);
@@ -544,8 +537,7 @@ void deleteprocs(void)
 { struct call_struc *cs, *cs1; 
   unsigned long flags;
 
-  save_flags(flags);
-  cli();
+  spin_lock_irqsave(&divert_lock, flags);
   cs = divert_head;
   divert_head = NULL;
   while (cs)
@@ -554,7 +546,7 @@ void deleteprocs(void)
      cs = cs->next;
      kfree(cs1);
    } 
-  restore_flags(flags);
+  spin_unlock_irqrestore(&divert_lock, flags);
 } /* deleteprocs */
 
 /****************************************************/
@@ -769,8 +761,8 @@ int prot_stat_callback(isdn_ctrl *ic)
    }  
 
   if (cs1->ics.driver == -1)
-   { save_flags(flags);
-     cli();
+   {
+     spin_lock_irqsave(&divert_lock, flags);
      del_timer(&cs1->timer);
      if (cs1->prev) 
        cs1->prev->next = cs1->next; /* forward link */
@@ -778,7 +770,7 @@ int prot_stat_callback(isdn_ctrl *ic)
        divert_head = cs1->next;
      if (cs1->next)
        cs1->next->prev = cs1->prev; /* back link */           
-     restore_flags(flags); 
+     spin_unlock_irqrestore(&divert_lock, flags);
      kfree(cs1);
    } 
 
@@ -826,15 +818,14 @@ int isdn_divert_stat_callback(isdn_ctrl *ic)
         cs = cs->next;
         if (cs1->ics.driver == -1)
           { 
-            save_flags(flags);
-            cli();
+            spin_lock_irqsave(&divert_lock, flags);
             if (cs1->prev) 
               cs1->prev->next = cs1->next; /* forward link */
             else
               divert_head = cs1->next;
             if (cs1->next)
               cs1->next->prev = cs1->prev; /* back link */           
-            restore_flags(flags); 
+            spin_unlock_irqrestore(&divert_lock, flags);
             kfree(cs1);
           } 
       }  
index 08df6f4..19439a6 100644 (file)
@@ -114,6 +114,8 @@ struct divert_info
 /**************/
 /* Prototypes */
 /**************/
+extern spinlock_t divert_lock;
+
 extern ulong if_used; /* number of interface users */
 extern int divert_dev_deinit(void);
 extern int divert_dev_init(void);
index 25f494a..29a32a8 100644 (file)
@@ -12,13 +12,13 @@ config CAPI_AVM
 
 config ISDN_DRV_AVMB1_B1ISA
        tristate "AVM B1 ISA support"
-       depends on CAPI_AVM && ISDN_CAPI && ISA && BROKEN_ON_SMP
+       depends on CAPI_AVM && ISDN_CAPI && ISA
        help
          Enable support for the ISA version of the AVM B1 card.
 
 config ISDN_DRV_AVMB1_B1PCI
        tristate "AVM B1 PCI support"
-       depends on CAPI_AVM && ISDN_CAPI && PCI && BROKEN_ON_SMP
+       depends on CAPI_AVM && ISDN_CAPI && PCI
        help
          Enable support for the PCI version of the AVM B1 card.
 
@@ -30,14 +30,14 @@ config ISDN_DRV_AVMB1_B1PCIV4
 
 config ISDN_DRV_AVMB1_T1ISA
        tristate "AVM T1/T1-B ISA support"
-       depends on CAPI_AVM && ISDN_CAPI && ISA && BROKEN_ON_SMP
+       depends on CAPI_AVM && ISDN_CAPI && ISA
        help
          Enable support for the AVM T1 T1B card.
          Note: This is a PRI card and handle 30 B-channels.
 
 config ISDN_DRV_AVMB1_B1PCMCIA
        tristate "AVM B1/M1/M2 PCMCIA support"
-       depends on CAPI_AVM && ISDN_CAPI && BROKEN_ON_SMP
+       depends on CAPI_AVM && ISDN_CAPI
        help
          Enable support for the PCMCIA version of the AVM B1 card.
 
@@ -50,14 +50,14 @@ config ISDN_DRV_AVMB1_AVM_CS
 
 config ISDN_DRV_AVMB1_T1PCI
        tristate "AVM T1/T1-B PCI support"
-       depends on CAPI_AVM && ISDN_CAPI && PCI && BROKEN_ON_SMP
+       depends on CAPI_AVM && ISDN_CAPI && PCI
        help
          Enable support for the AVM T1 T1B card.
          Note: This is a PRI card and handle 30 B-channels.
 
 config ISDN_DRV_AVMB1_C4
        tristate "AVM C4/C2 support"
-       depends on CAPI_AVM && ISDN_CAPI && PCI && BROKEN_ON_SMP
+       depends on CAPI_AVM && ISDN_CAPI && PCI
        help
          Enable support for the AVM C4/C2 PCI cards.
          These cards handle 4/2 BRI ISDN lines (8/4 channels).
index 72b57d4..0e40aca 100644 (file)
@@ -662,15 +662,16 @@ static void c4_handle_rx(avmcard *card)
 
 static irqreturn_t c4_handle_interrupt(avmcard *card)
 {
+       unsigned long flags;
        u32 status;
 
-       spin_lock(&card->lock);
+       spin_lock_irqsave(&card->lock, flags);
        status = c4inmeml(card->mbase+DOORBELL);
 
        if (status & DBELL_RESET_HOST) {
                u_int i;
                c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
-               spin_unlock(&card->lock);
+               spin_unlock_irqrestore(&card->lock, flags);
                if (card->nlogcontr == 0)
                        return IRQ_HANDLED;
                printk(KERN_ERR "%s: unexpected reset\n", card->name);
@@ -686,7 +687,7 @@ static irqreturn_t c4_handle_interrupt(avmcard *card)
 
        status &= (DBELL_UP_HOST | DBELL_DOWN_HOST);
        if (!status) {
-               spin_unlock(&card->lock);
+               spin_unlock_irqrestore(&card->lock, flags);
                return IRQ_HANDLED;
        }
        c4outmeml(card->mbase+DOORBELL, status);
@@ -709,7 +710,7 @@ static irqreturn_t c4_handle_interrupt(avmcard *card)
                        c4_dispatch_tx(card);
                }
        }
-       spin_unlock(&card->lock);
+       spin_unlock_irqrestore(&card->lock, flags);
        return IRQ_HANDLED;
 }
 
index b09e23e..cc0d510 100644 (file)
@@ -3,11 +3,11 @@
 #ifndef __DIVA_PCI_INTERFACE_H__
 #define __DIVA_PCI_INTERFACE_H__
 
-void *divasa_remap_pci_bar(diva_os_xdi_adapter_t *a,
+void __iomem *divasa_remap_pci_bar(diva_os_xdi_adapter_t *a,
                           int id,
                           unsigned long bar,
                           unsigned long area_length);
-void divasa_unmap_pci_bar(void *bar);
+void divasa_unmap_pci_bar(void __iomem *bar);
 unsigned long divasa_get_pci_irq(unsigned char bus,
                                 unsigned char func, void *pci_dev_handle);
 unsigned long divasa_get_pci_bar(unsigned char bus,
index 15bb9c6..8bdf971 100644 (file)
@@ -95,13 +95,13 @@ dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc)
  DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0]))
  for ( ; logCnt > 0 ; --logCnt )
  {
-  if ( !READ_WORD(&Xlog[logOut]) )
+  if ( !GET_WORD(&Xlog[logOut]) )
   {
    if ( --logCnt == 0 )
     break ;
    logOut = 0 ;
   }
-  if ( READ_WORD(&Xlog[logOut]) <= (logOut * sizeof(*Xlog)) )
+  if ( GET_WORD(&Xlog[logOut]) <= (logOut * sizeof(*Xlog)) )
   {
    if ( logCnt > 2 )
    {
@@ -110,9 +110,9 @@ dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc)
    }
    break ;
   }
-  logLen = (dword)(READ_WORD(&Xlog[logOut]) - (logOut * sizeof(*Xlog))) ;
+  logLen = (dword)(GET_WORD(&Xlog[logOut]) - (logOut * sizeof(*Xlog))) ;
   DBG_FTL_MXLOG(( (char *)&Xlog[logOut + 1], (dword)(logLen - 2) ))
-  logOut = (READ_WORD(&Xlog[logOut]) + 1) / sizeof(*Xlog) ;
+  logOut = (GET_WORD(&Xlog[logOut]) + 1) / sizeof(*Xlog) ;
  }
  DBG_FTL(("%s: ***************** end of XLOG *****************",
           &IoAdapter->Name[0]))
@@ -154,10 +154,10 @@ char *(ExceptionCauseTable[]) =
  "VCED"
 } ;
 void
-dump_trap_frame (PISDN_ADAPTER IoAdapter, byte *exceptionFrame)
+dump_trap_frame (PISDN_ADAPTER IoAdapter, byte __iomem *exceptionFrame)
 {
- MP_XCPTC *xcept = (MP_XCPTC *)exceptionFrame ;
- dword    *regs;
+ MP_XCPTC __iomem *xcept = (MP_XCPTC __iomem *)exceptionFrame ;
+ dword    __iomem *regs;
  regs  = &xcept->regs[0] ;
  DBG_FTL(("%s: ***************** CPU TRAPPED *****************",
           &IoAdapter->Name[0]))
@@ -595,26 +595,22 @@ Trapped:
 byte mem_in (ADAPTER *a, void *addr)
 {
  byte val;
- volatile byte* Base;
-
- Base = (volatile byte *)DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
- val = *(Base + (unsigned long)addr);
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ val = READ_BYTE(Base + (unsigned long)addr);
  DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
  return (val);
 }
 word mem_inw (ADAPTER *a, void *addr)
 {
  word val;
- volatile byte* Base;
- Base = (volatile byte*)DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
  val = READ_WORD((Base + (unsigned long)addr));
  DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
  return (val);
 }
 void mem_in_dw (ADAPTER *a, void *addr, dword* data, int dwords)
 {
- volatile byte* Base = (volatile byte*)DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
  while (dwords--) {
   *data++ = READ_DWORD((Base + (unsigned long)addr));
   addr+=4;
@@ -623,8 +619,8 @@ void mem_in_dw (ADAPTER *a, void *addr, dword* data, int dwords)
 }
 void mem_in_buffer (ADAPTER *a, void *addr, void *buffer, word length)
 {
- volatile byte* Base = (volatile byte*)DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
- memcpy (buffer, (void *)(Base + (unsigned long)addr), length);
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ memcpy_fromio(buffer, (Base + (unsigned long)addr), length);
  DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
 }
 void mem_look_ahead (ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
@@ -637,19 +633,19 @@ void mem_look_ahead (ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
 }
 void mem_out (ADAPTER *a, void *addr, byte data)
 {
- volatile byte* Base = (volatile byte*)DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
*(Base + (unsigned long)addr) = data ;
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
WRITE_BYTE(Base + (unsigned long)addr, data);
  DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
 }
 void mem_outw (ADAPTER *a, void *addr, word data)
 {
- volatile byte* Base = (volatile byte*)DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
  WRITE_WORD((Base + (unsigned long)addr), data);
  DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
 }
 void mem_out_dw (ADAPTER *a, void *addr, const dword* data, int dwords)
 {
- volatile byte* Base = (volatile byte*)DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
  while (dwords--) {
        WRITE_DWORD((Base + (unsigned long)addr), *data);
        addr+=4;
@@ -659,15 +655,15 @@ void mem_out_dw (ADAPTER *a, void *addr, const dword* data, int dwords)
 }
 void mem_out_buffer (ADAPTER *a, void *addr, void *buffer, word length)
 {
- volatile byte* Base = (volatile byte*)DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
- memcpy ((void *)(Base + (unsigned long)addr), buffer, length) ;
+ volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ memcpy_toio((Base + (unsigned long)addr), buffer, length) ;
  DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
 }
 void mem_inc (ADAPTER *a, void *addr)
 {
- volatile byte* Base = (volatile byte*)DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
- byte  x = *(Base + (unsigned long)addr);
*(Base + (unsigned long)addr) = x + 1 ;
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ byte  x = READ_BYTE(Base + (unsigned long)addr);
WRITE_BYTE(Base + (unsigned long)addr, x + 1);
  DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
 }
 /*------------------------------------------------------------------*/
@@ -676,7 +672,7 @@ void mem_inc (ADAPTER *a, void *addr)
 byte io_in(ADAPTER * a, void * adr)
 {
   byte val;
-  byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
   outppw(Port + 4, (word)(unsigned long)adr);
   val = inpp(Port);
   DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
@@ -685,7 +681,7 @@ byte io_in(ADAPTER * a, void * adr)
 word io_inw(ADAPTER * a, void * adr)
 {
   word val;
-  byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
   outppw(Port + 4, (word)(unsigned long)adr);
   val = inppw(Port);
   DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
@@ -693,7 +689,7 @@ word io_inw(ADAPTER * a, void * adr)
 }
 void io_in_buffer(ADAPTER * a, void * adr, void * buffer, word len)
 {
-  byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
   byte* P = (byte*)buffer;
   if ((long)adr & 1) {
     outppw(Port+4, (word)(unsigned long)adr);
@@ -712,7 +708,7 @@ void io_in_buffer(ADAPTER * a, void * adr, void * buffer, word len)
 }
 void io_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e)
 {
-  byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
   outppw(Port+4, (word)(unsigned long)RBuffer);
   ((PISDN_ADAPTER)a->io)->RBuffer.length = inppw(Port);
   inppw_buffer (Port, ((PISDN_ADAPTER)a->io)->RBuffer.P, ((PISDN_ADAPTER)a->io)->RBuffer.length + 1);
@@ -721,21 +717,21 @@ void io_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e)
 }
 void io_out(ADAPTER * a, void * adr, byte data)
 {
-  byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
   outppw(Port+4, (word)(unsigned long)adr);
   outpp(Port, data);
   DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
 }
 void io_outw(ADAPTER * a, void * adr, word data)
 {
-  byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
   outppw(Port+4, (word)(unsigned long)adr);
   outppw(Port, data);
   DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
 }
 void io_out_buffer(ADAPTER * a, void * adr, void * buffer, word len)
 {
-  byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
   byte* P = (byte*)buffer;
   if ((long)adr & 1) {
     outppw(Port+4, (word)(unsigned long)adr);
@@ -755,7 +751,7 @@ void io_out_buffer(ADAPTER * a, void * adr, void * buffer, word len)
 void io_inc(ADAPTER * a, void * adr)
 {
   byte x;
-  byte *Port = (byte*)DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
   outppw(Port+4, (word)(unsigned long)adr);
   x = inpp(Port);
   outppw(Port+4, (word)(unsigned long)adr);
@@ -865,7 +861,7 @@ void CALLBACK(ADAPTER * a, ENTITY * e)
 /* --------------------------------------------------------------------------
   routines for aligned reading and writing on RISC
   -------------------------------------------------------------------------- */
-void outp_words_from_buffer (word* adr, byte* P, dword len)
+void outp_words_from_buffer (word __iomem * adr, byte* P, dword len)
 {
   dword i = 0;
   word w;
@@ -875,7 +871,7 @@ void outp_words_from_buffer (word* adr, byte* P, dword len)
     outppw (adr, w);
   }
 }
-void inp_words_to_buffer (word* adr, byte* P, dword len)
+void inp_words_to_buffer (word __iomem * adr, byte* P, dword len)
 {
   dword i = 0;
   word w;
index 32ce17d..a6f2e8a 100644 (file)
@@ -97,15 +97,15 @@ struct _ISDN_ADAPTER {
  dword               downloadAddrTable[4] ; /* add. for MultiMaster */
  dword               MemoryBase ;
  dword               MemorySize ;
- byte                *Address ;
- byte                *Config ;
- byte                *Control ;
- byte                *reset ;
- byte                *port ;
- byte                *ram ;
- byte                *cfg ;
- byte                *prom ;
- byte                *ctlReg ;
+ byte                __iomem *Address ;
+ byte                __iomem *Config ;
+ byte                __iomem *Control ;
+ byte                __iomem *reset ;
+ byte                __iomem *port ;
+ byte                __iomem *ram ;
+ byte                __iomem *cfg ;
+ byte                __iomem *prom ;
+ byte                __iomem *ctlReg ;
  struct pc_maint  *pcm ;
  diva_os_dependent_devica_name_t os_name;
  byte                Name[32] ;
@@ -254,8 +254,8 @@ struct s_load {
 /* ---------------------------------------------------------------------
   Functions for port io
    --------------------------------------------------------------------- */
-void outp_words_from_buffer (word* adr, byte* P, dword len);
-void inp_words_to_buffer    (word* adr, byte* P, dword len);
+void outp_words_from_buffer (word __iomem * adr, byte* P, dword len);
+void inp_words_to_buffer    (word __iomem * adr, byte* P, dword len);
 /* ---------------------------------------------------------------------
   platform specific conversions
    --------------------------------------------------------------------- */
@@ -307,7 +307,7 @@ typedef struct {
  word  cnt ;
  word  out ;
 } Xdesc ;
-extern void     dump_trap_frame  (PISDN_ADAPTER IoAdapter, byte *exception) ;
+extern void     dump_trap_frame  (PISDN_ADAPTER IoAdapter, byte __iomem *exception) ;
 extern void     dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc) ;
 /* --------------------------------------------------------------------- */
 #endif  /* } __DIVA_XDI_COMMON_IO_H_INC__ */
index 0457682..3e279e1 100644 (file)
@@ -235,12 +235,12 @@ int diva_os_register_io_port (void *adapter, int register, unsigned long port,
 /*
 **  I/O port access abstraction
 */
-byte inpp (void*);
-word inppw (void*);
-void inppw_buffer (void*, void*, int);
-void outppw (void*, word);
-void outppw_buffer (void* , void*, int);
-void outpp (void*, word);
+byte inpp (void __iomem *);
+word inppw (void __iomem *);
+void inppw_buffer (void __iomem *, void*, int);
+void outppw (void __iomem *, word);
+void outppw_buffer (void __iomem * , void*, int);
+void outpp (void __iomem *, word);
 
 /*
 **  IRQ 
@@ -335,13 +335,35 @@ diva_os_atomic_decrement(diva_os_atomic_t* pv)
 
 /*
 ** endian macros
+**
+** If only...  In some cases we did use them for endianness conversion;
+** unfortunately, other uses were real iomem accesses.
 */
+#define READ_BYTE(addr)   readb(addr)
 #define READ_WORD(addr)   readw(addr)
 #define READ_DWORD(addr)  readl(addr)
 
+#define WRITE_BYTE(addr,v)  writeb(v,addr)
 #define WRITE_WORD(addr,v)  writew(v,addr)
 #define WRITE_DWORD(addr,v) writel(v,addr)
 
+static inline __u16 GET_WORD(void *addr)
+{
+       return le16_to_cpu(*(__le16 *)addr);
+}
+static inline __u32 GET_DWORD(void *addr)
+{
+       return le32_to_cpu(*(__le32 *)addr);
+}
+static inline void PUT_WORD(void *addr, __u16 v)
+{
+       *(__le16 *)addr = cpu_to_le16(v);
+}
+static inline void PUT_DWORD(void *addr, __u32 v)
+{
+       *(__le32 *)addr = cpu_to_le32(v);
+}
+
 /*
 ** 32/64 bit macors
 */
index b869651..62e3055 100644 (file)
@@ -45,7 +45,7 @@
                Recovery XLOG from QBRI Card
         -------------------------------------------------------------------------- */
 static void qBri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
-       byte  *base ;
+       byte  __iomem *base ;
        word *Xlog ;
        dword   regs[4], TrapID, offset, size ;
        Xdesc   xlogDesc ;
@@ -66,10 +66,10 @@ static void qBri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
                IoAdapter->trapped = 1 ;
        }
 
-       regs[0] = READ_DWORD((&base + offset) + 0x70);
-       regs[1] = READ_DWORD((&base + offset) + 0x74);
-       regs[2] = READ_DWORD((&base + offset) + 0x78);
-       regs[3] = READ_DWORD((&base + offset) + 0x7c);
+       regs[0] = READ_DWORD((base + offset) + 0x70);
+       regs[1] = READ_DWORD((base + offset) + 0x74);
+       regs[2] = READ_DWORD((base + offset) + 0x78);
+       regs[3] = READ_DWORD((base + offset) + 0x7c);
        regs[0] &= IoAdapter->MemorySize - 1 ;
 
        if ( (regs[0] >= offset)
@@ -83,7 +83,7 @@ static void qBri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
                size = offset + (IoAdapter->MemorySize >> factor) - regs[0] ;
                if ( size > MAX_XLOG_SIZE )
                        size = MAX_XLOG_SIZE ;
-               memcpy (Xlog, &base[regs[0]], size) ;
+               memcpy_fromio (Xlog, &base[regs[0]], size) ;
                xlogDesc.buf = Xlog ;
                xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]) ;
                xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]) ;
@@ -98,11 +98,11 @@ static void qBri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
                Reset QBRI Hardware
         -------------------------------------------------------------------------- */
 static void reset_qBri_hardware (PISDN_ADAPTER IoAdapter) {
-       word volatile *qBriReset ;
-       byte  volatile *qBriCntrl ;
-       byte  volatile *p ;
+       word volatile __iomem *qBriReset ;
+       byte  volatile __iomem *qBriCntrl ;
+       byte  volatile __iomem *p ;
 
-       qBriReset = (word volatile *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
+       qBriReset = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
        WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_SOFT_RESET) ;
        diva_os_wait (1) ;
        WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_SOFT_RESET) ;
@@ -126,10 +126,10 @@ static void reset_qBri_hardware (PISDN_ADAPTER IoAdapter) {
                Start Card CPU
         -------------------------------------------------------------------------- */
 void start_qBri_hardware (PISDN_ADAPTER IoAdapter) {
-       byte volatile *qBriReset ;
-       byte volatile *p ;
+       byte volatile __iomem *qBriReset ;
+       byte volatile __iomem *p ;
 
-       p = (byte volatile *)DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+       p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
        qBriReset = &p[(DIVA_4BRI_REVISION(IoAdapter)) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)];
        WRITE_DWORD(qBriReset, MQ_RISC_COLD_RESET_MASK) ;
        diva_os_wait (2) ;
@@ -144,10 +144,10 @@ void start_qBri_hardware (PISDN_ADAPTER IoAdapter) {
                Stop Card CPU
         -------------------------------------------------------------------------- */
 static void stop_qBri_hardware (PISDN_ADAPTER IoAdapter) {
-       byte volatile *p ;
-       dword volatile *qBriReset ;
-       dword volatile *qBriIrq ;
-       dword volatile *qBriIsacDspReset ;
+       byte volatile __iomem *p ;
+       dword volatile __iomem *qBriReset ;
+       dword volatile __iomem *qBriIrq ;
+       dword volatile __iomem *qBriIsacDspReset ;
        int rev2 = DIVA_4BRI_REVISION(IoAdapter);
        int reset_offset = rev2 ? (MQ2_BREG_RISC)      : (MQ_BREG_RISC);
        int irq_offset   = rev2 ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST);
@@ -155,9 +155,9 @@ static void stop_qBri_hardware (PISDN_ADAPTER IoAdapter) {
 
        if ( IoAdapter->ControllerNumber > 0 )
                return ;
-       p = (byte volatile *)DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
-       qBriReset = (dword volatile *)&p[reset_offset];
-       qBriIsacDspReset = (dword volatile *)&p[hw_offset];
+       p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+       qBriReset = (dword volatile __iomem *)&p[reset_offset];
+       qBriIsacDspReset = (dword volatile __iomem *)&p[hw_offset];
 /*
  *     clear interrupt line (reset Local Interrupt Test Register)
  */
@@ -165,12 +165,12 @@ static void stop_qBri_hardware (PISDN_ADAPTER IoAdapter) {
        WRITE_DWORD(qBriIsacDspReset, 0) ;
        DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
        
-       p = (byte volatile *)DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
-       p[PLX9054_INTCSR] = 0x00 ;      /* disable PCI interrupts */
+       p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+       WRITE_BYTE(&p[PLX9054_INTCSR], 0x00);   /* disable PCI interrupts */
        DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
        
-       p = (byte volatile *)DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
-       qBriIrq   = (dword volatile *)&p[irq_offset];
+       p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+       qBriIrq   = (dword volatile __iomem *)&p[irq_offset];
        WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
        DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
 
@@ -276,7 +276,7 @@ int qBri_FPGA_download (PISDN_ADAPTER IoAdapter) {
        int            bit ;
        byte           *File ;
        dword          code, FileLength ;
-       word volatile *addr = (word volatile *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
+       word volatile __iomem *addr = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
        word           val, baseval = FPGA_CS | FPGA_PROG ;
 
 
@@ -864,17 +864,17 @@ static int load_qBri_hardware (PISDN_ADAPTER IoAdapter) {
                Card ISR
         -------------------------------------------------------------------------- */
 static int qBri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
-       dword volatile     *qBriIrq ;
+       dword volatile     __iomem *qBriIrq ;
 
        PADAPTER_LIST_ENTRY QuadroList = IoAdapter->QuadroList ;
 
        word                    i ;
        int                     serviced = 0 ;
-       byte *p;
+       byte __iomem *p;
 
        p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
 
-       if ( !(p[PLX9054_INTCSR] & 0x80) ) {
+       if ( !(READ_BYTE(&p[PLX9054_INTCSR]) & 0x80) ) {
                DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
                return (0) ;
        }
@@ -884,7 +884,7 @@ static int qBri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
  *     clear interrupt line (reset Local Interrupt Test Register)
  */
        p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
-       qBriIrq = (dword volatile *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
+       qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
        WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
        DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
 
@@ -908,8 +908,8 @@ static int qBri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
                Does disable the interrupt on the card
         -------------------------------------------------------------------------- */
 static void disable_qBri_interrupt (PISDN_ADAPTER IoAdapter) {
-       dword volatile *qBriIrq ;
-       byte *p;
+       dword volatile __iomem *qBriIrq ;
+       byte __iomem *p;
 
        if ( IoAdapter->ControllerNumber > 0 )
                return ;
@@ -917,11 +917,11 @@ static void disable_qBri_interrupt (PISDN_ADAPTER IoAdapter) {
  *     clear interrupt line (reset Local Interrupt Test Register)
  */
        p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
-       p[PLX9054_INTCSR] = 0x00 ;      /* disable PCI interrupts */
+       WRITE_BYTE(&p[PLX9054_INTCSR], 0x00);   /* disable PCI interrupts */
        DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
 
        p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
-       qBriIrq = (dword volatile *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
+       qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
        WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
        DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
 }
index 7b5495f..693316c 100644 (file)
   Investigate card state, recovery trace buffer
   -------------------------------------------------------------------------- */
 static void bri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
- byte  *addrHi, *addrLo, *ioaddr ;
+ byte  __iomem *addrHi, *addrLo, *ioaddr ;
  word *Xlog ;
  dword   regs[4], i, size ;
  Xdesc   xlogDesc ;
- byte *Port;
+ byte __iomem *Port;
 /*
  * first read pointers and trap frame
  */
@@ -61,15 +61,15 @@ static void bri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
 /*
  * check for trapped MIPS 3xxx CPU, dump only exception frame
  */
- if ( READ_DWORD(&Xlog[0x80 / sizeof(Xlog[0])]) == 0x99999999 )
+ if ( GET_DWORD(&Xlog[0x80 / sizeof(Xlog[0])]) == 0x99999999 )
  {
   dump_trap_frame (IoAdapter, &((byte *)Xlog)[0x90]) ;
   IoAdapter->trapped = 1 ;
  }
- regs[0] = READ_DWORD(&((byte *)Xlog)[0x70]);
- regs[1] = READ_DWORD(&((byte *)Xlog)[0x74]);
- regs[2] = READ_DWORD(&((byte *)Xlog)[0x78]);
- regs[3] = READ_DWORD(&((byte *)Xlog)[0x7c]);
+ regs[0] = GET_DWORD(&((byte *)Xlog)[0x70]);
+ regs[1] = GET_DWORD(&((byte *)Xlog)[0x74]);
+ regs[2] = GET_DWORD(&((byte *)Xlog)[0x78]);
+ regs[3] = GET_DWORD(&((byte *)Xlog)[0x7c]);
  outpp (addrHi, (regs[1] >> 16) & 0x7F) ;
  outppw (addrLo, regs[1] & 0xFFFF) ;
  xlogDesc.cnt = inppw(ioaddr) ;
@@ -102,7 +102,7 @@ static void bri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
    Reset hardware
   --------------------------------------------------------------------- */
 static void reset_bri_hardware (PISDN_ADAPTER IoAdapter) {
- byte *p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+ byte __iomem *p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
  outpp (p, 0x00) ;
  DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
 }
@@ -110,7 +110,7 @@ static void reset_bri_hardware (PISDN_ADAPTER IoAdapter) {
    Halt system
   --------------------------------------------------------------------- */
 static void stop_bri_hardware (PISDN_ADAPTER IoAdapter) {
- byte *p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+ byte __iomem *p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
  if (p) {
   outpp (p, 0x00) ; /* disable interrupts ! */
  }
@@ -471,7 +471,7 @@ static int load_bri_hardware (PISDN_ADAPTER IoAdapter) {
 #endif /* } */
 /******************************************************************************/
 static int bri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
- byte *p;
+ byte __iomem *p;
 
  p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
  if ( !(inpp (p) & 0x01) ) {
@@ -493,7 +493,7 @@ static int bri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
   Disable IRQ in the card hardware
   -------------------------------------------------------------------------- */
 static void disable_bri_interrupt (PISDN_ADAPTER IoAdapter) {
- byte *p;
+ byte __iomem *p;
  p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
  if ( p )
  {
index e1f13e0..bdc031b 100644 (file)
@@ -47,7 +47,7 @@ static dword pri_ram_offset (ADAPTER* a) {
   Recovery XLOG buffer from the card
   ------------------------------------------------------------------------- */
 static void pri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
- byte  *base ;
+ byte  __iomem *base ;
  word *Xlog ;
  dword   regs[4], TrapID, size ;
  Xdesc   xlogDesc ;
@@ -75,7 +75,7 @@ static void pri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
   size = IoAdapter->MemorySize - regs[0] ;
   if ( size > MAX_XLOG_SIZE )
    size = MAX_XLOG_SIZE ;
-  memcpy (Xlog, &base[regs[0]], size) ;
+  memcpy_fromio(Xlog, &base[regs[0]], size) ;
   xlogDesc.buf = Xlog ;
   xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]) ;
   xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]) ;
@@ -89,10 +89,10 @@ static void pri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
   Hardware reset of PRI card
   ------------------------------------------------------------------------- */
 static void reset_pri_hardware (PISDN_ADAPTER IoAdapter) {
- byte *p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
*p = _MP_RISC_RESET | _MP_LED1 | _MP_LED2 ;
+ byte __iomem *p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
WRITE_BYTE(p, _MP_RISC_RESET | _MP_LED1 | _MP_LED2);
  diva_os_wait (50) ;
*p = 0x00 ;
WRITE_BYTE(p, 0x00);
  diva_os_wait (50) ;
  DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
 }
@@ -101,10 +101,10 @@ static void reset_pri_hardware (PISDN_ADAPTER IoAdapter) {
   ------------------------------------------------------------------------- */
 static void stop_pri_hardware (PISDN_ADAPTER IoAdapter) {
  dword i;
- byte *p;
- dword volatile *cfgReg = (dword volatile *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
cfgReg[3] = 0x00000000 ;
cfgReg[1] = 0x00000000 ;
+ byte __iomem *p;
+ dword volatile __iomem *cfgReg = (void __iomem *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
WRITE_DWORD(&cfgReg[3], 0);
WRITE_DWORD(&cfgReg[1], 0);
  DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfgReg);
  IoAdapter->a.ram_out (&IoAdapter->a, &RAM->SWReg, SWREG_HALT_CPU) ;
  i = 0 ;
@@ -114,12 +114,12 @@ static void stop_pri_hardware (PISDN_ADAPTER IoAdapter) {
   i++ ;
  }
  DBG_TRC(("%s: PRI stopped (%d)", IoAdapter->Name, i))
- cfgReg = (dword volatile *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
+ cfgReg = (void __iomem *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
  WRITE_DWORD(&cfgReg[0],((dword)(~0x03E00000)));
  DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfgReg);
  diva_os_wait (1) ;
  p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
*p = _MP_RISC_RESET | _MP_LED1 | _MP_LED2 ;
WRITE_BYTE(p, _MP_RISC_RESET | _MP_LED1 | _MP_LED2);
  DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
 }
 #if !defined(DIVA_USER_MODE_CARD_CONFIG) /* { */
@@ -491,15 +491,15 @@ static int load_pri_hardware (PISDN_ADAPTER IoAdapter) {
   PRI Adapter interrupt Service Routine
    -------------------------------------------------------------------------- */
 static int pri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
- byte *cfg = DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
- if ( !((READ_DWORD((dword *)cfg)) & 0x80000000) ) {
+ byte __iomem *cfg = DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
+ if ( !(READ_DWORD(cfg) & 0x80000000) ) {
   DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfg);
   return (0) ;
  }
  /*
   clear interrupt line
   */
- WRITE_DWORD(((dword *)cfg), (dword)~0x03E00000) ;
+ WRITE_DWORD(cfg, (dword)~0x03E00000) ;
  DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfg);
  IoAdapter->IrqCount++ ;
  if ( IoAdapter->Initialized )
@@ -512,9 +512,9 @@ static int pri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
   Disable interrupt in the card hardware
   ------------------------------------------------------------------------- */
 static void disable_pri_interrupt (PISDN_ADAPTER IoAdapter) {
- dword volatile *cfgReg = (dword volatile *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter) ;
cfgReg[3] = 0x00000000 ;
cfgReg[1] = 0x00000000 ;
+ dword volatile __iomem *cfgReg = (dword volatile __iomem *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter) ;
WRITE_DWORD(&cfgReg[3], 0);
WRITE_DWORD(&cfgReg[1], 0);
  WRITE_DWORD(&cfgReg[0], (dword)(~0x03E00000)) ;
  DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfgReg);
 }
index e7d9bbc..a3bd163 100644 (file)
@@ -12,7 +12,7 @@ typedef struct _divas_pci_card_resources {
        void *hdev;
 
        dword bar[8];           /* contains context of appropriate BAR Register */
-       void *addr[8];          /* same bar, but mapped into memory */
+       void __iomem *addr[8];          /* same bar, but mapped into memory */
        dword length[8];        /* bar length */
        int mem_type_id[MAX_MEM_TYPE];
        unsigned int qoffset;
index 7791223..c4f861a 100644 (file)
@@ -316,14 +316,14 @@ Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
                                                                QuickHex(t, cs->rcvbuf, cs->rcvidx);
                                                                debugl1(cs, cs->dlog);
                                                        }
-                                                        /* moves recieved data in sk-buffer */
+                                                        /* moves received data in sk-buffer */
                                                        memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
                                                        skb_queue_tail(&cs->rq, skb);
                                                }
                                        }
 
                                }
-                                /* throw damaged packets away, reset recieve-buffer, indicate RX */
+                                /* throw damaged packets away, reset receive-buffer, indicate RX */
                                ptr = cs->rcvbuf;
                                cs->rcvidx = 0;
                                schedule_event(cs, D_RCVBUFREADY);
index 3a6acde..6fcb2cf 100644 (file)
@@ -794,13 +794,13 @@ setup_avm_pcipnp(struct IsdnCard *card)
 #ifdef CONFIG_PCI
        if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
                PCI_DEVICE_ID_AVM_A1,  dev_avm))) {
+               if (pci_enable_device(dev_avm))
+                       return(0);
                cs->irq = dev_avm->irq;
                if (!cs->irq) {
                        printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
                        return(0);
                }
-               if (pci_enable_device(dev_avm))
-                       return(0);
                cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
                if (!cs->hw.avm.cfg_reg) {
                        printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
index 3b526d7..2127146 100644 (file)
@@ -691,8 +691,7 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                                byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
                                byteout(cs->hw.elsa.timer, 0);
                                spin_unlock_irqrestore(&cs->lock, flags);
-                               set_current_state(TASK_UNINTERRUPTIBLE);
-                               schedule_timeout((110*HZ)/1000);
+                               msleep(110);
                                spin_lock_irqsave(&cs->lock, flags);
                                cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
                                byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
index 3946536..c2db526 100644 (file)
@@ -1619,8 +1619,7 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        inithfcpci(cs);
                        reset_hfcpci(cs);
                        spin_unlock_irqrestore(&cs->lock, flags);
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout((80 * HZ) / 1000);     /* Timeout 80ms */
+                       msleep(80);                             /* Timeout 80ms */
                        /* now switch timer interrupt off */
                        spin_lock_irqsave(&cs->lock, flags);
                        cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
index 07a07aa..685fcc2 100644 (file)
@@ -314,8 +314,7 @@ release_io_hfcsx(struct IsdnCardState *cs)
        cs->hw.hfcsx.int_m2 = 0;        /* interrupt output off ! */
        Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
        Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout((30 * HZ) / 1000);     /* Timeout 30ms */
+       msleep(30);                             /* Timeout 30ms */
        Write_hfc(cs, HFCSX_CIRM, 0);   /* Reset Off */
        del_timer(&cs->hw.hfcsx.timer);
        release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */
@@ -1367,8 +1366,7 @@ hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        spin_lock_irqsave(&cs->lock, flags);
                        inithfcsx(cs);
                        spin_unlock_irqrestore(&cs->lock, flags);
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout((80 * HZ) / 1000);     /* Timeout 80ms */
+                       msleep(80);                             /* Timeout 80ms */
                        /* now switch timer interrupt off */
                        spin_lock_irqsave(&cs->lock, flags);
                        cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
index ea8da99..6fc55fe 100644 (file)
@@ -125,8 +125,7 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        init2bds0(cs);
                        spin_unlock_irqrestore(&cs->lock, flags);
                        delay = (80*HZ)/1000 +1;
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout((80*HZ)/1000);
+                       msleep(80);
                        spin_lock_irqsave(&cs->lock, flags);
                        cs->hw.hfcD.ctmt |= HFCD_TIM800;
                        cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 
index 221d3d7..dc57917 100644 (file)
@@ -580,7 +580,7 @@ struct teles3_hw {
 
 struct teles0_hw {
        unsigned int cfg_reg;
-       unsigned long membase;
+       void __iomem *membase;
        unsigned long phymem;
 };
 
@@ -751,8 +751,8 @@ struct hfcD_hw {
 struct isurf_hw {
        unsigned int reset;
        unsigned long phymem;
-       unsigned long isac;
-       unsigned long isar;
+       void __iomem *isac;
+       void __iomem *isar;
        struct isar_reg isar_r;
 };
 
index 98c408e..987d441 100644 (file)
@@ -996,28 +996,18 @@ static struct pci_driver fcpci_driver = {
 
 static int __init hisax_fcpcipnp_init(void)
 {
-       int retval, pci_nr_found;
+       int retval;
 
        printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n");
 
        retval = pci_register_driver(&fcpci_driver);
-       if (retval < 0)
+       if (retval)
                goto out;
-       pci_nr_found = retval;
-       retval = 0;
-
 #ifdef __ISAPNP__
        retval = pnp_register_driver(&fcpnp_driver);
        if (retval < 0)
                goto out_unregister_pci;
 #endif
-
-#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
-       if (pci_nr_found + retval == 0) {
-               retval = -ENODEV;
-               goto out_unregister_isapnp;
-       }
-#endif
        return 0;
 
 #if !defined(CONFIG_HOTPLUG) || defined(MODULE)
index c2759f7..af5171d 100644 (file)
@@ -126,7 +126,7 @@ void
 release_io_isurf(struct IsdnCardState *cs)
 {
        release_region(cs->hw.isurf.reset, 1);
-       iounmap((unsigned char *)cs->hw.isurf.isar);
+       iounmap(cs->hw.isurf.isar);
        release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
 }
 
@@ -272,8 +272,7 @@ setup_isurf(struct IsdnCard *card)
                release_region(cs->hw.isurf.reset, 1);
                return (0);
        }
-       cs->hw.isurf.isar =
-               (unsigned long) ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
+       cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
        cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
        printk(KERN_INFO
               "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
index d7ca342..5ec5ec3 100644 (file)
@@ -30,65 +30,65 @@ const char *teles0_revision = "$Revision: 2.15.2.4 $";
 #define bytein(addr) inb(addr)
 
 static inline u_char
-readisac(unsigned long adr, u_char off)
+readisac(void __iomem *adr, u_char off)
 {
        return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
 }
 
 static inline void
-writeisac(unsigned long adr, u_char off, u_char data)
+writeisac(void __iomem *adr, u_char off, u_char data)
 {
        writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
 }
 
 
 static inline u_char
-readhscx(unsigned long adr, int hscx, u_char off)
+readhscx(void __iomem *adr, int hscx, u_char off)
 {
        return readb(adr + (hscx ? 0x1c0 : 0x180) +
                     ((off & 1) ? 0x1ff : 0) + off);
 }
 
 static inline void
-writehscx(unsigned long adr, int hscx, u_char off, u_char data)
+writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
 {
        writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
               ((off & 1) ? 0x1ff : 0) + off); mb();
 }
 
 static inline void
-read_fifo_isac(unsigned long adr, u_char * data, int size)
+read_fifo_isac(void __iomem *adr, u_char * data, int size)
 {
        register int i;
-       register u_char *ad = (u_char *)adr + 0x100;
+       register u_char __iomem *ad = adr + 0x100;
        for (i = 0; i < size; i++)
                data[i] = readb(ad);
 }
 
 static inline void
-write_fifo_isac(unsigned long adr, u_char * data, int size)
+write_fifo_isac(void __iomem *adr, u_char * data, int size)
 {
        register int i;
-       register u_char *ad = (u_char *)adr + 0x100;
+       register u_char __iomem *ad = adr + 0x100;
        for (i = 0; i < size; i++) {
                writeb(data[i], ad); mb();
        }
 }
 
 static inline void
-read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
+read_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
 {
        register int i;
-       register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
+       register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
        for (i = 0; i < size; i++)
                data[i] = readb(ad);
 }
 
 static inline void
-write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
+write_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
 {
        int i;
-       register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
+       register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
        for (i = 0; i < size; i++) {
                writeb(data[i], ad); mb();
        }
@@ -188,7 +188,7 @@ release_io_teles0(struct IsdnCardState *cs)
 {
        if (cs->hw.teles0.cfg_reg)
                release_region(cs->hw.teles0.cfg_reg, 8);
-       iounmap((unsigned char *)cs->hw.teles0.membase);
+       iounmap(cs->hw.teles0.membase);
        release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
 }
 
@@ -336,10 +336,9 @@ setup_teles0(struct IsdnCard *card)
                        release_region(cs->hw.teles0.cfg_reg, 8);
                return (0);
        }
-       cs->hw.teles0.membase =
-               (unsigned long) ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
+       cs->hw.teles0.membase = ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
        printk(KERN_INFO
-              "HiSax: %s config irq:%d mem:0x%lX cfg:0x%X\n",
+              "HiSax: %s config irq:%d mem:%p cfg:0x%X\n",
               CardType[cs->typ], cs->irq,
               cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
        if (reset_teles0(cs)) {
index 7713c46..0661c6c 100644 (file)
@@ -43,7 +43,7 @@ const char *telespci_revision = "$Revision: 2.23.2.3 $";
                                } while (portdata & ZORAN_PO_RQ_PEN)
 
 static inline u_char
-readisac(unsigned long adr, u_char off)
+readisac(void __iomem *adr, u_char off)
 {
        register unsigned int portdata;
 
@@ -60,7 +60,7 @@ readisac(unsigned long adr, u_char off)
 }
 
 static inline void
-writeisac(unsigned long adr, u_char off, u_char data)
+writeisac(void __iomem *adr, u_char off, u_char data)
 {
        register unsigned int portdata;
 
@@ -76,7 +76,7 @@ writeisac(unsigned long adr, u_char off, u_char data)
 }
 
 static inline u_char
-readhscx(unsigned long adr, int hscx, u_char off)
+readhscx(void __iomem *adr, int hscx, u_char off)
 {
        register unsigned int portdata;
 
@@ -92,7 +92,7 @@ readhscx(unsigned long adr, int hscx, u_char off)
 }
 
 static inline void
-writehscx(unsigned long adr, int hscx, u_char off, u_char data)
+writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
 {
        register unsigned int portdata;
 
@@ -107,7 +107,7 @@ writehscx(unsigned long adr, int hscx, u_char off, u_char data)
 }
 
 static inline void
-read_fifo_isac(unsigned long adr, u_char * data, int size)
+read_fifo_isac(void __iomem *adr, u_char * data, int size)
 {
        register unsigned int portdata;
        register int i;
@@ -125,7 +125,7 @@ read_fifo_isac(unsigned long adr, u_char * data, int size)
 }
 
 static void
-write_fifo_isac(unsigned long adr, u_char * data, int size)
+write_fifo_isac(void __iomem *adr, u_char * data, int size)
 {
        register unsigned int portdata;
        register int i;
@@ -142,7 +142,7 @@ write_fifo_isac(unsigned long adr, u_char * data, int size)
 }
 
 static inline void
-read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
+read_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
 {
        register unsigned int portdata;
        register int i;
@@ -160,7 +160,7 @@ read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 }
 
 static inline void
-write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
+write_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
 {
        unsigned int portdata;
        register int i;
@@ -260,7 +260,7 @@ telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 void
 release_io_telespci(struct IsdnCardState *cs)
 {
-       iounmap((void *)cs->hw.teles0.membase);
+       iounmap(cs->hw.teles0.membase);
 }
 
 static int
@@ -309,7 +309,7 @@ setup_telespci(struct IsdnCard *card)
                        printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
                        return(0);
                }
-               cs->hw.teles0.membase = (u_long) ioremap(pci_resource_start(dev_tel, 0),
+               cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0),
                        PAGE_SIZE);
                printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
                        pci_resource_start(dev_tel, 0), dev_tel->irq);
@@ -333,7 +333,7 @@ setup_telespci(struct IsdnCard *card)
        /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
 
        printk(KERN_INFO
-              "HiSax: %s config irq:%d mem:%lx\n",
+              "HiSax: %s config irq:%d mem:%p\n",
               CardType[cs->typ], cs->irq,
               cs->hw.teles0.membase);
 
index 2f27315..e19a01a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 #include "hysdn_defs.h"
@@ -246,8 +247,7 @@ ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
                /* the interrupts are still masked */
 
                sti();
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout((20 * HZ) / 1000);     /* Timeout 20ms */
+               msleep_interruptible(20);               /* Timeout 20ms */
 
                if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) {
                        if (card->debug_flags & LOG_POF_CARD)
@@ -386,8 +386,7 @@ ergo_waitpofready(struct HYSDN_CARD *card)
                        return (0);     /* success */
                }               /* data has arrived */
                sti();
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout((50 * HZ) / 1000);     /* Timeout 50ms */
+               msleep_interruptible(50);               /* Timeout 50ms */
        }                       /* wait until timeout */
 
        if (card->debug_flags & LOG_POF_CARD)
index 4f63903..8ee25b2 100644 (file)
@@ -246,8 +246,6 @@ hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl,
        rp->level3cnt = MaxLogicalConnections;
        memcpy(&hycapi_applications[appl-1].rp, 
               rp, sizeof(capi_register_params));
-       
-/*        MOD_INC_USE_COUNT; */
 }
 
 /*********************************************************************
@@ -311,7 +309,6 @@ hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl)
        {
                hycapi_release_internal(ctrl, appl);
        }
-/*        MOD_DEC_USE_COUNT;  */
 }
 
 
index 1a2015e..4fa3b01 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 #include "hysdn_defs.h"
@@ -160,8 +161,7 @@ hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan)
                if (card->debug_flags & LOG_SCHED_ASYN)
                        hysdn_addlog(card, "async tx-cfg delayed");
 
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout((20 * HZ) / 1000);     /* Timeout 20ms */
+               msleep_interruptible(20);               /* Timeout 20ms */
                if (!--cnt) {
                        restore_flags(flags);
                        return (-ERR_ASYNC_TIME);       /* timed out */
@@ -190,8 +190,7 @@ hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan)
                if (card->debug_flags & LOG_SCHED_ASYN)
                        hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
 
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout((20 * HZ) / 1000);     /* Timeout 20ms */
+               msleep_interruptible(20);               /* Timeout 20ms */
                if (!--cnt) {
                        restore_flags(flags);
                        return (-ERR_ASYNC_TIME);       /* timed out */
index 4071c43..3ac15d9 100644 (file)
@@ -99,7 +99,7 @@ config ISDN_DRV_LOOP
 
 config ISDN_DIVERSION
        tristate "Support isdn diversion services"
-       depends on BROKEN && BROKEN_ON_SMP
+       depends on ISDN && ISDN_I4L
        help
          This option allows you to use some supplementary diversion
          services in conjunction with the HiSax driver on an EURO/DSS1
index 16fda69..baf4bca 100644 (file)
@@ -68,9 +68,9 @@
 #include <linux/errno.h>
 #include <linux/string.h>      /* used in new tty drivers */
 #include <linux/signal.h>      /* used in new tty drivers */
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/types.h>
 
@@ -364,7 +364,7 @@ static void *bsd_alloc (struct isdn_ppp_comp_data *data)
                db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
                        sizeof (db->lens[0]));
                if (!db->lens) {
-                       bsd_free (db); /* calls MOD_DEC_USE_COUNT; */
+                       bsd_free (db);
                        return (NULL);
                }
        }
index 4ab15c9..2854831 100644 (file)
@@ -70,8 +70,7 @@ typedef struct icn_cdef {
 #define ICN_FLAGS_RUNNING  4    /* Cards driver activated                  */
 #define ICN_FLAGS_RBTIMER  8    /* cyclic scheduling of B-Channel-poll     */
 
-#define ICN_BOOT_TIMEOUT1  (HZ) /* Delay for Boot-download (jiffies)       */
-#define ICN_CHANLOCK_DELAY (HZ/10)     /* Delay for Channel-mapping (jiffies)     */
+#define ICN_BOOT_TIMEOUT1  1000 /* Delay for Boot-download (msecs)         */
 
 #define ICN_TIMER_BCREAD (HZ/100)      /* B-Channel poll-cycle                    */
 #define ICN_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle                    */
index bdb27fa..8e44928 100644 (file)
  * We need these if they're not already included
  */
 #include <linux/timer.h>
+#include <linux/time.h>
 #include <linux/isdnif.h>
 #include "message.h"
 
 /*
  * Amount of time to wait for a reset to complete
  */
-#define CHECKRESET_TIME                milliseconds(4000)
+#define CHECKRESET_TIME                msecs_to_jiffies(4000)
 
 /*
  * Amount of time between line status checks
  */
-#define CHECKSTAT_TIME         milliseconds(8000)
+#define CHECKSTAT_TIME         msecs_to_jiffies(8000)
 
 /*
  * The maximum amount of time to wait for a message response
  * to arrive. Use exclusively by send_and_receive
  */
-#define SAR_TIMEOUT            milliseconds(10000)
+#define SAR_TIMEOUT            msecs_to_jiffies(10000)
 
 /*
  * Macro to determine is a card id is valid
index 930845c..a10c6af 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 #include "includes.h"
 #include "hardware.h"
 #include "card.h"
@@ -167,8 +168,7 @@ static int __init sc_init(void)
                if(do_reset) {
                        pr_debug("Doing a SAFE probe reset\n");
                        outb(0xFF, io[b] + RESET_OFFSET);
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(milliseconds(10000));
+                       msleep_interruptible(10000);
                }
                pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b],
                        ram[b] == 0 ? "will" : "won't");
@@ -500,8 +500,7 @@ int identify_board(unsigned long rambase, unsigned int iobase)
         * Try to identify a PRI card
         */
        outb(PRI_BASEPG_VAL, pgport);
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(HZ);
+       msleep_interruptible(1000);
        sig = readl(rambase + SIG_OFFSET);
        pr_debug("Looking for a signature, got 0x%x\n", sig);
        if(sig == SIGNATURE)
@@ -511,8 +510,7 @@ int identify_board(unsigned long rambase, unsigned int iobase)
         * Try to identify a PRI card
         */
        outb(BRI_BASEPG_VAL, pgport);
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(HZ);
+       msleep_interruptible(1000);
        sig = readl(rambase + SIG_OFFSET);
        pr_debug("Looking for a signature, got 0x%x\n", sig);
        if(sig == SIGNATURE)
index b418d37..7788f42 100644 (file)
@@ -88,10 +88,10 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
        tpam_card *card, *c;
        int i, err;
 
-       if (pci_enable_device(dev)) {
+       if ((err = pci_enable_device(dev))) {
                printk(KERN_ERR "TurboPAM: can't enable PCI device at %s\n",
                        pci_name(dev));
-               return -ENODEV;
+               return err;
        }
 
        /* allocate memory for the board structure */
@@ -118,7 +118,7 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
        }
 
        /* remap board memory */
-       if (!(card->bar0 = (unsigned long) ioremap(pci_resource_start(dev, 0),
+       if (!(card->bar0 = ioremap(pci_resource_start(dev, 0),
                                                   0x800000))) {
                printk(KERN_ERR "TurboPAM: tpam_register_card: "
                       "unable to remap bar0\n");
@@ -130,12 +130,12 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
        readl(card->bar0 + TPAM_RESETPAM_REGISTER);
 
        /* initialisation magic :-( */
-       copy_to_pam_dword(card, (void *)0x01800008, 0x00000030);
-       copy_to_pam_dword(card, (void *)0x01800010, 0x00000030);
-       copy_to_pam_dword(card, (void *)0x01800014, 0x42240822);
-       copy_to_pam_dword(card, (void *)0x01800018, 0x07114000);
-       copy_to_pam_dword(card, (void *)0x0180001c, 0x00000400);
-       copy_to_pam_dword(card, (void *)0x01840070, 0x00000010);
+       copy_to_pam_dword(card, 0x01800008, 0x00000030);
+       copy_to_pam_dword(card, 0x01800010, 0x00000030);
+       copy_to_pam_dword(card, 0x01800014, 0x42240822);
+       copy_to_pam_dword(card, 0x01800018, 0x07114000);
+       copy_to_pam_dword(card, 0x0180001c, 0x00000400);
+       copy_to_pam_dword(card, 0x01840070, 0x00000010);
 
        /* fill the ISDN link layer structure */
        card->interface.owner = THIS_MODULE;
@@ -201,7 +201,7 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
        return 0;
 
 err_out_iounmap:
-       iounmap((void *)card->bar0);
+       iounmap(card->bar0);
 
 err_out_free_irq:
        free_irq(card->irq, card);
@@ -231,7 +231,7 @@ static void __devexit tpam_unregister_card(struct pci_dev *pcidev, tpam_card *ca
        free_irq(card->irq, card);
 
        /* release mapped memory */
-       iounmap((void *)card->bar0);
+       iounmap(card->bar0);
 
        pci_disable_device(pcidev);
 }
index 69a6bd4..de4904f 100644 (file)
@@ -84,7 +84,7 @@ struct sk_buff *build_ACreateNCOReq(const u8 *phone) {
        struct sk_buff *skb;
        u8 *tlv;
 
-       dprintk("TurboPAM(build_ACreateNCOReq): phone=%s\n", phone);
+       pr_debug("TurboPAM(build_ACreateNCOReq): phone=%s\n", phone);
 
        /* build the NCO packet */
        if (!(skb = build_NCOpacket(ID_ACreateNCOReq, 23 + strlen(phone), 0, 0, 0))) 
@@ -141,7 +141,7 @@ struct sk_buff *build_ADestroyNCOReq(u32 ncoid) {
        struct sk_buff *skb;
        u8 *tlv;
 
-       dprintk("TurboPAM(build_ADestroyNCOReq): ncoid=%lu\n", 
+       pr_debug("TurboPAM(build_ADestroyNCOReq): ncoid=%lu\n",
                (unsigned long)ncoid);
 
        /* build the NCO packet */
@@ -170,7 +170,7 @@ struct sk_buff *build_CConnectReq(u32 ncoid, const u8 *called, u8 hdlc) {
        struct sk_buff *skb;
        u8 *tlv;
 
-       dprintk("TurboPAM(build_CConnectReq): ncoid=%lu, called=%s, hdlc=%d\n",
+       pr_debug("TurboPAM(build_CConnectReq): ncoid=%lu, called=%s, hdlc=%d\n",
                (unsigned long)ncoid, called, hdlc);
 
        /* build the NCO packet */
@@ -220,7 +220,7 @@ struct sk_buff *build_CConnectRsp(u32 ncoid) {
        struct sk_buff *skb;
        u8 *tlv;
 
-       dprintk("TurboPAM(build_CConnectRsp): ncoid=%lu\n",
+       pr_debug("TurboPAM(build_CConnectRsp): ncoid=%lu\n",
                (unsigned long)ncoid);
 
        /* build the NCO packet */
@@ -247,7 +247,7 @@ struct sk_buff *build_CDisconnectReq(u32 ncoid) {
        struct sk_buff *skb;
        u8 *tlv;
 
-       dprintk("TurboPAM(build_CDisconnectReq): ncoid=%lu\n",
+       pr_debug("TurboPAM(build_CDisconnectReq): ncoid=%lu\n",
                (unsigned long)ncoid);
 
        /* build the NCO packet */
@@ -274,7 +274,7 @@ struct sk_buff *build_CDisconnectRsp(u32 ncoid) {
        struct sk_buff *skb;
        u8 *tlv;
 
-       dprintk("TurboPAM(build_CDisconnectRsp): ncoid=%lu\n",
+       pr_debug("TurboPAM(build_CDisconnectRsp): ncoid=%lu\n",
                (unsigned long)ncoid);
 
        /* build the NCO packet */
@@ -307,7 +307,7 @@ struct sk_buff *build_U3DataReq(u32 ncoid, void *data, u16 len,
        u8 *tlv;
        void *p;
 
-       dprintk("TurboPAM(build_U3DataReq): "
+       pr_debug("TurboPAM(build_U3DataReq): "
                "ncoid=%lu, len=%d, ack=%d, ack_size=%d\n", 
                (unsigned long)ncoid, len, ack, ack_size);
 
@@ -397,7 +397,7 @@ int parse_ACreateNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
        }
 
        if (*status) {
-               dprintk("TurboPAM(parse_ACreateNCOCnf): status=%d\n", *status);
+               pr_debug("TurboPAM(parse_ACreateNCOCnf): status=%d\n", *status);
                return 0;
        }
 
@@ -408,7 +408,7 @@ int parse_ACreateNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
                return -1;
        }
 
-       dprintk("TurboPAM(parse_ACreateNCOCnf): ncoid=%lu, status=%d\n",
+       pr_debug("TurboPAM(parse_ACreateNCOCnf): ncoid=%lu, status=%d\n",
                (unsigned long)*ncoid, *status);
        return 0;
 }
@@ -432,7 +432,7 @@ int parse_ADestroyNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
        }
 
        if (*status) {
-               dprintk("TurboPAM(parse_ADestroyNCOCnf): status=%d\n", *status);
+               pr_debug("TurboPAM(parse_ADestroyNCOCnf): status=%d\n", *status);
                return 0;
        }
 
@@ -443,7 +443,7 @@ int parse_ADestroyNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
                return -1;
        }
 
-       dprintk("TurboPAM(parse_ADestroyNCOCnf): ncoid=%lu, status=%d\n", 
+       pr_debug("TurboPAM(parse_ADestroyNCOCnf): ncoid=%lu, status=%d\n",
                (unsigned long)*ncoid, *status);
        return 0;
 }
@@ -464,7 +464,7 @@ int parse_CConnectCnf(struct sk_buff *skb, u32 *ncoid) {
                       "NCOID not found\n");
                return -1;
        }
-       dprintk("TurboPAM(parse_CConnectCnf): ncoid=%lu\n", 
+       pr_debug("TurboPAM(parse_CConnectCnf): ncoid=%lu\n",
                (unsigned long)*ncoid);
        return 0;
 }
@@ -522,7 +522,7 @@ int parse_CConnectInd(struct sk_buff *skb, u32 *ncoid, u8 *hdlc,
        }
        memcpy(called, phone + 2, PHONE_MAXIMUMSIZE);
 
-       dprintk("TurboPAM(parse_CConnectInd): "
+       pr_debug("TurboPAM(parse_CConnectInd): "
                "ncoid=%lu, hdlc=%d, plan=%d, scr=%d, calling=%s, called=%s\n",
                (unsigned long)*ncoid, *hdlc, *plan, *screen, calling, called);
        return 0;
@@ -553,7 +553,7 @@ int parse_CDisconnectCnf(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
                return -1;
        }
 
-       dprintk("TurboPAM(parse_CDisconnectCnf): ncoid=%lu, causetopuf=%lu\n", 
+       pr_debug("TurboPAM(parse_CDisconnectCnf): ncoid=%lu, causetopuf=%lu\n",
                (unsigned long)*ncoid, (unsigned long)*causetopuf);
        return 0;
 }
@@ -583,7 +583,7 @@ int parse_CDisconnectInd(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
                return -1;
        }
 
-       dprintk("TurboPAM(parse_CDisconnectInd): ncoid=%lu, causetopuf=%lu\n", 
+       pr_debug("TurboPAM(parse_CDisconnectInd): ncoid=%lu, causetopuf=%lu\n",
                (unsigned long)*ncoid, (unsigned long)*causetopuf);
        return 0;
 }
@@ -613,7 +613,7 @@ int parse_U3ReadyToReceiveInd(struct sk_buff *skb, u32 *ncoid, u8 *ready) {
                return -1;
        }
 
-       dprintk("TurboPAM(parse_U3ReadyToReceiveInd): ncoid=%lu, ready=%d\n", 
+       pr_debug("TurboPAM(parse_U3ReadyToReceiveInd): ncoid=%lu, ready=%d\n",
                (unsigned long)*ncoid, *ready);
        return 0;
 }
@@ -644,7 +644,7 @@ int parse_U3DataInd(struct sk_buff *skb, u32 *ncoid, u8 **data, u16 *len) {
                 sizeof(skb_header) + sizeof(pci_mpb) + p->actualBlockTLVSize);
        *data = skb->data;
 
-       dprintk("TurboPAM(parse_U3DataInd): ncoid=%lu, datalen=%d\n", 
+       pr_debug("TurboPAM(parse_U3DataInd): ncoid=%lu, datalen=%d\n",
                (unsigned long)*ncoid, *len);
        return 0;
 }
index 9b55684..35add91 100644 (file)
@@ -30,7 +30,7 @@ static int tpam_sendpacket(tpam_card *card, tpam_channel *channel);
  */
 void tpam_enqueue(tpam_card *card, struct sk_buff *skb) {
 
-       dprintk("TurboPAM(tpam_enqueue): card=%d\n", card->id);
+       pr_debug("TurboPAM(tpam_enqueue): card=%d\n", card->id);
 
        /* queue the sk_buff on the board's send queue */
        skb_queue_tail(&card->sendq, skb);
@@ -49,7 +49,7 @@ void tpam_enqueue(tpam_card *card, struct sk_buff *skb) {
  */
 void tpam_enqueue_data(tpam_channel *channel, struct sk_buff *skb) {
        
-       dprintk("TurboPAM(tpam_enqueue_data): card=%d, channel=%d\n", 
+       pr_debug("TurboPAM(tpam_enqueue_data): card=%d, channel=%d\n",
                channel->card->id, channel->num);
 
        /* if existant, queue the sk_buff on the channel's send queue */
@@ -84,30 +84,30 @@ irqreturn_t tpam_irq(int irq, void *dev_id, struct pt_regs *regs)
        pci_mpb mpb;
        skb_header *skbh;
 
-       dprintk("TurboPAM(tpam_irq): IRQ received, card=%d\n", card->id);
+       pr_debug("TurboPAM(tpam_irq): IRQ received, card=%d\n", card->id);
 
        /* grab the board lock */
        spin_lock(&card->lock);
 
        /* get the message type */
-       ackupload = copy_from_pam_dword(card, (void *)TPAM_ACKUPLOAD_REGISTER);
+       ackupload = copy_from_pam_dword(card, TPAM_ACKUPLOAD_REGISTER);
 
        /* acknowledge the interrupt */
-       copy_to_pam_dword(card, (void *)TPAM_INTERRUPTACK_REGISTER, 0);
+       copy_to_pam_dword(card, TPAM_INTERRUPTACK_REGISTER, 0);
        readl(card->bar0 + TPAM_HINTACK_REGISTER);
 
        if (!ackupload) {
                /* it is a new message from the board */
                
-               dprintk("TurboPAM(tpam_irq): message received, card=%d\n", 
+               pr_debug("TurboPAM(tpam_irq): message received, card=%d\n",
                        card->id);
 
                /* get the upload pointer */
                uploadptr = copy_from_pam_dword(card, 
-                                           (void *)TPAM_UPLOADPTR_REGISTER);
+                                           TPAM_UPLOADPTR_REGISTER);
                
                /* get the beginning of the message (pci_mpb part) */
-               copy_from_pam(card, &mpb, (void *)uploadptr, sizeof(pci_mpb));
+               copy_from_pam(card, &mpb, uploadptr, sizeof(pci_mpb));
 
                /* allocate the sk_buff */
                if (!(skb = alloc_skb(sizeof(skb_header) + sizeof(pci_mpb) + 
@@ -131,13 +131,13 @@ irqreturn_t tpam_irq(int irq, void *dev_id, struct pt_regs *regs)
 
                /* copy the TLV block into the sk_buff */
                copy_from_pam(card, skb_put(skb, mpb.actualBlockTLVSize),
-                             (void *)uploadptr + sizeof(pci_mpb), 
+                             uploadptr + sizeof(pci_mpb), 
                              mpb.actualBlockTLVSize);
 
                /* if existent, copy the data block into the sk_buff */
                if (mpb.actualDataSize)
                        copy_from_pam(card, skb_put(skb, mpb.actualDataSize),
-                               (void *)uploadptr + sizeof(pci_mpb) + 4096, 
+                               uploadptr + sizeof(pci_mpb) + 4096, 
                                mpb.actualDataSize);
 
                /* wait for the board to become ready */
@@ -154,7 +154,7 @@ irqreturn_t tpam_irq(int irq, void *dev_id, struct pt_regs *regs)
                } while (hpic & 0x00000002);
 
                /* acknowledge the message */
-               copy_to_pam_dword(card, (void *)TPAM_ACKDOWNLOAD_REGISTER, 
+               copy_to_pam_dword(card, TPAM_ACKDOWNLOAD_REGISTER, 
                                  0xffffffff);
                readl(card->bar0 + TPAM_DSPINT_REGISTER);
 
@@ -176,7 +176,7 @@ irqreturn_t tpam_irq(int irq, void *dev_id, struct pt_regs *regs)
        else {
                /* it is a ack from the board */
 
-               dprintk("TurboPAM(tpam_irq): message acknowledged, card=%d\n",
+               pr_debug("TurboPAM(tpam_irq): message acknowledged, card=%d\n",
                        card->id);
 
                /* board is not busy anymore */
@@ -231,7 +231,7 @@ void tpam_recv_tq(tpam_card *card) {
                                tpam_recv_U3DataInd(card, skb);
                                break;
                        default:
-                               dprintk("TurboPAM(tpam_recv_tq): "
+                               pr_debug("TurboPAM(tpam_recv_tq): "
                                        "unknown messageID %d, card=%d\n", 
                                        p->messageID, card->id);
                                break;
@@ -286,13 +286,13 @@ static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) {
        skb_header *skbh;
        u32 waiting_too_long;
 
-       dprintk("TurboPAM(tpam_sendpacket), card=%d, channel=%d\n", 
+       pr_debug("TurboPAM(tpam_sendpacket), card=%d, channel=%d\n",
                card->id, channel ? channel->num : -1);
 
        if (channel) {
                /* dequeue a packet from the channel's send queue */
                if (!(skb = skb_dequeue(&channel->sendq))) {
-                       dprintk("TurboPAM(tpam_sendpacket): "
+                       pr_debug("TurboPAM(tpam_sendpacket): "
                                "card=%d, channel=%d, no packet\n", 
                                card->id, channel->num);
                        return 0;
@@ -301,7 +301,7 @@ static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) {
                /* if the channel is not ready to receive, requeue the packet
                 * and return 0 to give a chance to another channel */
                if (!channel->readytoreceive) {
-                       dprintk("TurboPAM(tpam_sendpacket): "
+                       pr_debug("TurboPAM(tpam_sendpacket): "
                                "card=%d, channel=%d, channel not ready\n",
                                card->id, channel->num);
                        skb_queue_head(&channel->sendq, skb);
@@ -314,7 +314,7 @@ static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) {
                /* if the board is busy, requeue the packet and return 1 since
                 * there is no need to try another channel */
                if (card->busy) {
-                       dprintk("TurboPAM(tpam_sendpacket): "
+                       pr_debug("TurboPAM(tpam_sendpacket): "
                                "card=%d, channel=%d, card busy\n",
                                card->id, channel->num);
                        skb_queue_head(&channel->sendq, skb);
@@ -325,7 +325,7 @@ static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) {
        else {
                /* dequeue a packet from the board's send queue */
                if (!(skb = skb_dequeue(&card->sendq))) {
-                       dprintk("TurboPAM(tpam_sendpacket): "
+                       pr_debug("TurboPAM(tpam_sendpacket): "
                                "card=%d, no packet\n", card->id);
                        return 0;
                }
@@ -336,7 +336,7 @@ static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) {
                /* if the board is busy, requeue the packet and return 1 since
                 * there is no need to try another channel */
                if (card->busy) {
-                       dprintk("TurboPAM(tpam_sendpacket): "
+                       pr_debug("TurboPAM(tpam_sendpacket): "
                                "card=%d, card busy\n", card->id);
                        skb_queue_head(&card->sendq, skb);
                        spin_unlock_irq(&card->lock);
@@ -357,20 +357,19 @@ static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) {
        } while (hpic & 0x00000002);
 
        skbh = (skb_header *)skb->data;
-       dprintk("TurboPAM(tpam_sendpacket): "
+       pr_debug("TurboPAM(tpam_sendpacket): "
                "card=%d, card ready, sending %d/%d bytes\n", 
                card->id, skbh->size, skbh->data_size);
 
        /* get the board's download pointer */
-               downloadptr = copy_from_pam_dword(card, 
-                                         (void *)TPAM_DOWNLOADPTR_REGISTER);
+               downloadptr = copy_from_pam_dword(card, TPAM_DOWNLOADPTR_REGISTER);
 
        /* copy the packet to the board at the downloadptr location */
-               copy_to_pam(card, (void *)downloadptr, skb->data + sizeof(skb_header), 
+               copy_to_pam(card, downloadptr, skb->data + sizeof(skb_header), 
                    skbh->size);
        if (skbh->data_size)
                /* if there is some data in the packet, copy it too */
-               copy_to_pam(card, (void *)downloadptr + sizeof(pci_mpb) + 4096,
+               copy_to_pam(card, downloadptr + sizeof(pci_mpb) + 4096,
                            skb->data + sizeof(skb_header) + skbh->size, 
                            skbh->data_size);
 
@@ -378,7 +377,7 @@ static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) {
        card->busy = 1;
 
        /* interrupt the board */
-       copy_to_pam_dword(card, (void *)TPAM_ACKDOWNLOAD_REGISTER, 0);
+       copy_to_pam_dword(card, TPAM_ACKDOWNLOAD_REGISTER, 0);
        readl(card->bar0 + TPAM_DSPINT_REGISTER);
 
        /* release the lock */
index 26bdcd7..c5adb05 100644 (file)
@@ -23,7 +23,7 @@
 
 static unsigned long anslcd_short_delay = 80;
 static unsigned long anslcd_long_delay = 3280;
-static volatile unsigned charanslcd_ptr;
+static volatile unsigned char __iomem *anslcd_ptr;
 
 #undef DEBUG
 
@@ -151,12 +151,12 @@ anslcd_init(void)
        if (strcmp(node->parent->name, "gc"))
                return -ENODEV;
 
-       anslcd_ptr = (volatile unsigned char*)ioremap(ANSLCD_ADDR, 0x20);
+       anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
        
        retval = misc_register(&anslcd_dev);
        if(retval < 0){
                printk(KERN_INFO "LCD: misc_register failed\n");
-               iounmap((void *)anslcd_ptr);
+               iounmap(anslcd_ptr);
                return retval;
        }
 
@@ -179,7 +179,7 @@ static void __exit
 anslcd_exit(void)
 {
        misc_deregister(&anslcd_dev);
-       iounmap((void *)anslcd_ptr);
+       iounmap(anslcd_ptr);
 }
 
 module_init(anslcd_init);
index 5283a6d..d4e651b 100644 (file)
@@ -57,7 +57,7 @@ struct adb_regs {
 /* Bits in autopoll register */
 #define APE    1               /* autopoll enable */
 
-static volatile struct adb_regs *adb;
+static volatile struct adb_regs __iomem *adb;
 static struct adb_request *current_req, *last_req;
 static spinlock_t macio_lock = SPIN_LOCK_UNLOCKED;
 
@@ -105,8 +105,7 @@ int macio_init(void)
        printk("\n"); }
 #endif
        
-       adb = (volatile struct adb_regs *)
-               ioremap(adbs->addrs->address, sizeof(struct adb_regs));
+       adb = ioremap(adbs->addrs->address, sizeof(struct adb_regs));
 
        out_8(&adb->ctrl.r, 0);
        out_8(&adb->intr.r, 0);
@@ -202,7 +201,7 @@ static irqreturn_t macio_adb_interrupt(int irq, void *arg,
                                       struct pt_regs *regs)
 {
        int i, n, err;
-       struct adb_request *req;
+       struct adb_request *req = NULL;
        unsigned char ibuf[16];
        int ibuf_len = 0;
        int complete = 0;
index a3a5372..ad0f620 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/console.h>
 #endif
 #include <linux/slab.h>
+#include <linux/bitops.h>
 
 #include <asm/sections.h>
 #include <asm/io.h>
@@ -40,7 +41,6 @@
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/segment.h>
-#include <asm/bitops.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <linux/adb.h>
@@ -1461,7 +1461,7 @@ static void rs_flush_chars(struct tty_struct *tty)
        spin_unlock_irqrestore(&info->lock, flags);
 }
 
-static int rs_write(struct tty_struct * tty, int from_user,
+static int rs_write(struct tty_struct * tty,
                    const unsigned char *buf, int count)
 {
        int     c, ret = 0;
@@ -1474,51 +1474,22 @@ static int rs_write(struct tty_struct * tty, int from_user,
        if (!tty || !info->xmit_buf || !tmp_buf)
                return 0;
 
-       if (from_user) {
-               down(&tmp_buf_sem);
-               while (1) {
-                       c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                                 SERIAL_XMIT_SIZE - info->xmit_head));
-                       if (c <= 0)
-                               break;
-
-                       c -= copy_from_user(tmp_buf, buf, c);
-                       if (!c) {
-                               if (!ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-                       spin_lock_irqsave(&info->lock, flags);
-                       c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                             SERIAL_XMIT_SIZE - info->xmit_head));
-                       memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-                       info->xmit_head = ((info->xmit_head + c) &
-                                          (SERIAL_XMIT_SIZE-1));
-                       info->xmit_cnt += c;
-                       spin_unlock_irqrestore(&info->lock, flags);
-                       buf += c;
-                       count -= c;
-                       ret += c;
-               }
-               up(&tmp_buf_sem);
-       } else {
-               while (1) {
-                       spin_lock_irqsave(&info->lock, flags);
-                       c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                                 SERIAL_XMIT_SIZE - info->xmit_head));
-                       if (c <= 0) {
-                               spin_unlock_irqrestore(&info->lock, flags);
-                               break;
-                       }
-                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
-                       info->xmit_head = ((info->xmit_head + c) &
-                                          (SERIAL_XMIT_SIZE-1));
-                       info->xmit_cnt += c;
+       while (1) {
+               spin_lock_irqsave(&info->lock, flags);
+               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                         SERIAL_XMIT_SIZE - info->xmit_head));
+               if (c <= 0) {
                        spin_unlock_irqrestore(&info->lock, flags);
-                       buf += c;
-                       count -= c;
-                       ret += c;
+                       break;
                }
+               memcpy(info->xmit_buf + info->xmit_head, buf, c);
+               info->xmit_head = ((info->xmit_head + c) &
+                                  (SERIAL_XMIT_SIZE-1));
+               info->xmit_cnt += c;
+               spin_unlock_irqrestore(&info->lock, flags);
+               buf += c;
+               count -= c;
+               ret += c;
        }
        spin_lock_irqsave(&info->lock, flags);
        if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
index eda488a..1a4c71a 100644 (file)
@@ -119,18 +119,33 @@ static char * critical_overtemp_path = "/sbin/critical_overtemp";
 #define ADC_CPU_CURRENT_SCALE  0x1f40  /* _AD4 */
 
 /*
- * PID factors for the U3/Backside fan control loop
+ * PID factors for the U3/Backside fan control loop. We have 2 sets
+ * of values here, one set for U3 and one set for U3H
  */
-#define BACKSIDE_FAN_PWM_ID            1
-#define BACKSIDE_PID_G_d               0x02800000
+#define BACKSIDE_FAN_PWM_DEFAULT_ID    1
+#define BACKSIDE_FAN_PWM_INDEX         0
+#define BACKSIDE_PID_U3_G_d            0x02800000
+#define BACKSIDE_PID_U3H_G_d           0x01400000
 #define BACKSIDE_PID_G_p               0x00500000
 #define BACKSIDE_PID_G_r               0x00000000
-#define BACKSIDE_PID_INPUT_TARGET      0x00410000
+#define BACKSIDE_PID_U3_INPUT_TARGET   0x00410000
+#define BACKSIDE_PID_U3H_INPUT_TARGET  0x004b0000
 #define BACKSIDE_PID_INTERVAL          5
 #define BACKSIDE_PID_OUTPUT_MAX                100
-#define BACKSIDE_PID_OUTPUT_MIN                20
+#define BACKSIDE_PID_U3_OUTPUT_MIN     20
+#define BACKSIDE_PID_U3H_OUTPUT_MIN    30
 #define BACKSIDE_PID_HISTORY_SIZE      2
 
+struct basckside_pid_params
+{
+       s32                     G_d;
+       s32                     G_p;
+       s32                     G_r;
+       s32                     input_target;
+       s32                     output_min;
+       s32                     output_max;
+};
+
 struct backside_pid_state
 {
        int                     ticks;
@@ -146,7 +161,8 @@ struct backside_pid_state
 /*
  * PID factors for the Drive Bay fan control loop
  */
-#define DRIVES_FAN_RPM_ID                      2
+#define DRIVES_FAN_RPM_DEFAULT_ID      2
+#define DRIVES_FAN_RPM_INDEX           1
 #define DRIVES_PID_G_d                 0x01e00000
 #define DRIVES_PID_G_p                 0x00500000
 #define DRIVES_PID_G_r                 0x00000000
@@ -168,7 +184,8 @@ struct drives_pid_state
        int                     first;
 };
 
-#define SLOTS_FAN_PWM_ID                       2
+#define SLOTS_FAN_PWM_DEFAULT_ID       2
+#define SLOTS_FAN_PWM_INDEX            2
 #define        SLOTS_FAN_DEFAULT_PWM           50 /* Do better here ! */
 
 /*
@@ -191,10 +208,15 @@ struct drives_pid_state
  * CPU B FAKE POWER    49      (I_V_inputs: 18, 19)
  */
 
-#define CPUA_INTAKE_FAN_RPM_ID         3
-#define CPUA_EXHAUST_FAN_RPM_ID                4
-#define CPUB_INTAKE_FAN_RPM_ID         5
-#define CPUB_EXHAUST_FAN_RPM_ID                6
+#define CPUA_INTAKE_FAN_RPM_DEFAULT_ID 3
+#define CPUA_EXHAUST_FAN_RPM_DEFAULT_ID        4
+#define CPUB_INTAKE_FAN_RPM_DEFAULT_ID 5
+#define CPUB_EXHAUST_FAN_RPM_DEFAULT_ID        6
+
+#define CPUA_INTAKE_FAN_RPM_INDEX      3
+#define CPUA_EXHAUST_FAN_RPM_INDEX     4
+#define CPUB_INTAKE_FAN_RPM_INDEX      5
+#define CPUB_EXHAUST_FAN_RPM_INDEX     6
 
 #define CPU_INTAKE_SCALE               0x0000f852
 #define CPU_TEMP_HISTORY_SIZE          2
@@ -202,6 +224,11 @@ struct drives_pid_state
 #define CPU_PID_INTERVAL               1
 #define CPU_MAX_OVERTEMP               30
 
+#define CPUA_PUMP_RPM_INDEX            7
+#define CPUB_PUMP_RPM_INDEX            8
+#define CPU_PUMP_OUTPUT_MAX            3700
+#define CPU_PUMP_OUTPUT_MIN            1000
+
 struct cpu_pid_state
 {
        int                     index;
@@ -219,6 +246,7 @@ struct cpu_pid_state
        s32                     voltage;
        s32                     current_a;
        s32                     last_temp;
+       s32                     last_power;
        int                     first;
        u8                      adc_config;
 };
index 7dbc5cb..897902b 100644 (file)
@@ -353,12 +353,12 @@ do_detach( struct i2c_client *client )
 }
 
 static struct i2c_driver g4fan_driver = {  
-       .name           = "Apple G4 Thermostat/Fan",
+       .owner          = THIS_MODULE,
+       .name           = "therm_windtunnel",
        .id             = I2C_DRIVERID_G4FAN,
        .flags          = I2C_DF_NOTIFY,
-       .attach_adapter = &do_attach,
-       .detach_client  = &do_detach,
-       .command        = NULL,
+       .attach_adapter = do_attach,
+       .detach_client  = do_detach,
 };
 
 static int
index 7072313..e5e3d02 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/system.h>
 #include <linux/init.h>
 
-static volatile unsigned char *via;
+static volatile unsigned char __iomem *via;
 static spinlock_t cuda_lock = SPIN_LOCK_UNLOCKED;
 
 #ifdef CONFIG_MAC
@@ -160,7 +160,7 @@ find_via_cuda(void)
        if (vias->n_addrs < 1 || vias->n_intrs < 1)
            return 0;
     }
-    via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
+    via = ioremap(vias->addrs->address, 0x2000);
 
     cuda_state = idle;
     sys_ctrler = SYS_CTRLER_CUDA;
index 9f4147e..85e3756 100644 (file)
@@ -72,7 +72,7 @@
 /* How many iterations between battery polls */
 #define BATTERY_POLLING_COUNT  2
 
-static volatile unsigned char *via;
+static volatile unsigned char __iomem *via;
 
 /* VIA registers - spaced 0x200 bytes apart */
 #define RS             0x200           /* skip between registers */
@@ -141,7 +141,7 @@ static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
 static int pmu_fully_inited = 0;
 static int pmu_has_adb;
-static unsigned char *gpio_reg = NULL;
+static unsigned char __iomem *gpio_reg = NULL;
 static int gpio_irq = -1;
 static int gpio_irq_enabled = -1;
 static volatile int pmu_suspended = 0;
@@ -153,8 +153,8 @@ static int drop_interrupts;
 static int option_lid_wakeup = 1;
 static int sleep_in_progress;
 static int can_sleep;
-static unsigned long async_req_locks;
 #endif /* CONFIG_PMAC_PBOOK */
+static unsigned long async_req_locks;
 static unsigned int pmu_irq_stats[11];
 
 static struct proc_dir_entry *proc_pmu_root;
@@ -352,7 +352,7 @@ find_via_pmu(void)
        } else
                pmu_kind = PMU_UNKNOWN;
 
-       via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
+       via = ioremap(vias->addrs->address, 0x2000);
        
        out_8(&via[IER], IER_CLR | 0x7f);       /* disable all intrs */
        out_8(&via[IFR], 0x7f);                 /* clear IFR */
@@ -1164,7 +1164,7 @@ wait_for_ack(void)
 static inline void
 send_byte(int x)
 {
-       volatile unsigned char *v = via;
+       volatile unsigned char __iomem *v = via;
 
        out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);
        out_8(&v[SR], x);
@@ -1175,7 +1175,7 @@ send_byte(int x)
 static inline void
 recv_byte(void)
 {
-       volatile unsigned char *v = via;
+       volatile unsigned char __iomem *v = via;
 
        out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);
        in_8(&v[SR]);           /* resets SR */
@@ -2630,8 +2630,8 @@ powerbook_sleep_3400(void)
        unsigned int hid0;
        unsigned long p;
        struct adb_request sleep_req;
-       char *mem_ctrl;
-       unsigned int *mem_ctrl_sleep;
+       void __iomem *mem_ctrl;
+       unsigned int __iomem *mem_ctrl_sleep;
 
        /* first map in the memory controller registers */
        mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);
@@ -2639,7 +2639,7 @@ powerbook_sleep_3400(void)
                printk("powerbook_sleep_3400: ioremap failed\n");
                return -ENOMEM;
        }
-       mem_ctrl_sleep = (unsigned int *) (mem_ctrl + PB3400_MEM_CTRL_SLEEP);
+       mem_ctrl_sleep = mem_ctrl + PB3400_MEM_CTRL_SLEEP;
 
        /* Allocate room for PCI save */
        pbook_alloc_pci_save();
@@ -2977,7 +2977,7 @@ void pmu_device_init(void)
 
 #ifdef DEBUG_SLEEP
 static inline void  __pmac
-polled_handshake(volatile unsigned char *via)
+polled_handshake(volatile unsigned char __iomem *via)
 {
        via[B] &= ~TREQ; eieio();
        while ((via[B] & TACK) != 0)
@@ -2988,7 +2988,7 @@ polled_handshake(volatile unsigned char *via)
 }
 
 static inline void  __pmac
-polled_send_byte(volatile unsigned char *via, int x)
+polled_send_byte(volatile unsigned char __iomem *via, int x)
 {
        via[ACR] |= SR_OUT | SR_EXT; eieio();
        via[SR] = x; eieio();
@@ -2996,7 +2996,7 @@ polled_send_byte(volatile unsigned char *via, int x)
 }
 
 static inline int __pmac
-polled_recv_byte(volatile unsigned char *via)
+polled_recv_byte(volatile unsigned char __iomem *via)
 {
        int x;
 
@@ -3012,7 +3012,7 @@ pmu_polled_request(struct adb_request *req)
 {
        unsigned long flags;
        int i, l, c;
-       volatile unsigned char *v = via;
+       volatile unsigned char __iomem *v = via;
 
        req->complete = 1;
        c = req->data[0];
index a17b253..ebf7351 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2003 Christophe Saout <christophe@saout.de>
+ * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
  *
  * This file is released under the GPL.
  */
@@ -15,6 +16,7 @@
 #include <linux/workqueue.h>
 #include <asm/atomic.h>
 #include <asm/scatterlist.h>
+#include <asm/page.h>
 
 #include "dm.h"
 
@@ -40,12 +42,22 @@ struct convert_context {
        struct bio *bio_out;
        unsigned int offset_in;
        unsigned int offset_out;
-       int idx_in;
-       int idx_out;
+       unsigned int idx_in;
+       unsigned int idx_out;
        sector_t sector;
        int write;
 };
 
+struct crypt_config;
+
+struct crypt_iv_operations {
+       int (*ctr)(struct crypt_config *cc, struct dm_target *ti,
+                  const char *opts);
+       void (*dtr)(struct crypt_config *cc);
+       const char *(*status)(struct crypt_config *cc);
+       int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
+};
+
 /*
  * Crypt: maps a linear range of a block device
  * and encrypts / decrypts at the same time.
@@ -64,11 +76,14 @@ struct crypt_config {
        /*
         * crypto related data
         */
-       struct crypto_tfm *tfm;
+       struct crypt_iv_operations *iv_gen_ops;
+       char *iv_mode;
+       void *iv_gen_private;
        sector_t iv_offset;
-       int (*iv_generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
-       int iv_size;
-       int key_size;
+       unsigned int iv_size;
+
+       struct crypto_tfm *tfm;
+       unsigned int key_size;
        u8 key[0];
 };
 
@@ -93,18 +108,129 @@ static void mempool_free_page(void *page, void *data)
 
 
 /*
- * Different IV generation algorithms
+ * Different IV generation algorithms:
+ *
+ * plain: the initial vector is the 32-bit low-endian version of the sector
+ *        number, padded with zeros if neccessary.
+ *
+ * ess_iv: "encrypted sector|salt initial vector", the sector number is
+ *         encrypted with the bulk cipher using a salt as key. The salt
+ *         should be derived from the bulk cipher's key via hashing.
+ *
+ * plumb: unimplemented, see:
+ * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
  */
-static int crypt_iv_plain(struct crypt_config *cc, u8 *iv, sector_t sector)
+
+static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
 {
+       memset(iv, 0, cc->iv_size);
        *(u32 *)iv = cpu_to_le32(sector & 0xffffffff);
-       if (cc->iv_size > sizeof(u32) / sizeof(u8))
-               memset(iv + (sizeof(u32) / sizeof(u8)), 0,
-                      cc->iv_size - (sizeof(u32) / sizeof(u8)));
 
        return 0;
 }
 
+static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
+                             const char *opts)
+{
+       struct crypto_tfm *essiv_tfm;
+       struct crypto_tfm *hash_tfm;
+       struct scatterlist sg;
+       unsigned int saltsize;
+       u8 *salt;
+
+       if (opts == NULL) {
+               ti->error = PFX "Digest algorithm missing for ESSIV mode";
+               return -EINVAL;
+       }
+
+       /* Hash the cipher key with the given hash algorithm */
+       hash_tfm = crypto_alloc_tfm(opts, 0);
+       if (hash_tfm == NULL) {
+               ti->error = PFX "Error initializing ESSIV hash";
+               return -EINVAL;
+       }
+
+       if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) {
+               ti->error = PFX "Expected digest algorithm for ESSIV hash";
+               crypto_free_tfm(hash_tfm);
+               return -EINVAL;
+       }
+
+       saltsize = crypto_tfm_alg_digestsize(hash_tfm);
+       salt = kmalloc(saltsize, GFP_KERNEL);
+       if (salt == NULL) {
+               ti->error = PFX "Error kmallocing salt storage in ESSIV";
+               crypto_free_tfm(hash_tfm);
+               return -ENOMEM;
+       }
+
+       sg.page = virt_to_page(cc->key);
+       sg.offset = offset_in_page(cc->key);
+       sg.length = cc->key_size;
+       crypto_digest_digest(hash_tfm, &sg, 1, salt);
+       crypto_free_tfm(hash_tfm);
+
+       /* Setup the essiv_tfm with the given salt */
+       essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm),
+                                    CRYPTO_TFM_MODE_ECB);
+       if (essiv_tfm == NULL) {
+               ti->error = PFX "Error allocating crypto tfm for ESSIV";
+               kfree(salt);
+               return -EINVAL;
+       }
+       if (crypto_tfm_alg_blocksize(essiv_tfm)
+           != crypto_tfm_alg_ivsize(cc->tfm)) {
+               ti->error = PFX "Block size of ESSIV cipher does "
+                               "not match IV size of block cipher";
+               crypto_free_tfm(essiv_tfm);
+               kfree(salt);
+               return -EINVAL;
+       }
+       if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) {
+               ti->error = PFX "Failed to set key for ESSIV cipher";
+               crypto_free_tfm(essiv_tfm);
+               kfree(salt);
+               return -EINVAL;
+       }
+       kfree(salt);
+
+       cc->iv_gen_private = (void *)essiv_tfm;
+       return 0;
+}
+
+static void crypt_iv_essiv_dtr(struct crypt_config *cc)
+{
+       crypto_free_tfm((struct crypto_tfm *)cc->iv_gen_private);
+       cc->iv_gen_private = NULL;
+}
+
+static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+{
+       struct scatterlist sg = { NULL, };
+
+       memset(iv, 0, cc->iv_size);
+       *(u64 *)iv = cpu_to_le64(sector);
+
+       sg.page = virt_to_page(iv);
+       sg.offset = offset_in_page(iv);
+       sg.length = cc->iv_size;
+       crypto_cipher_encrypt((struct crypto_tfm *)cc->iv_gen_private,
+                             &sg, &sg, cc->iv_size);
+
+       return 0;
+}
+
+static struct crypt_iv_operations crypt_iv_plain_ops = {
+       .generator = crypt_iv_plain_gen
+};
+
+static struct crypt_iv_operations crypt_iv_essiv_ops = {
+       .ctr       = crypt_iv_essiv_ctr,
+       .dtr       = crypt_iv_essiv_dtr,
+       .generator = crypt_iv_essiv_gen
+};
+
+
 static inline int
 crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
                           struct scatterlist *in, unsigned int length,
@@ -113,8 +239,8 @@ crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
        u8 iv[cc->iv_size];
        int r;
 
-       if (cc->iv_generator) {
-               r = cc->iv_generator(cc, iv, sector);
+       if (cc->iv_gen_ops) {
+               r = cc->iv_gen_ops->generator(cc, iv, sector);
                if (r < 0)
                        return r;
 
@@ -200,13 +326,13 @@ static int crypt_convert(struct crypt_config *cc,
  */
 static struct bio *
 crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
-                   struct bio *base_bio, int *bio_vec_idx)
+                   struct bio *base_bio, unsigned int *bio_vec_idx)
 {
        struct bio *bio;
-       int nr_iovecs = dm_div_up(size, PAGE_SIZE);
+       unsigned int nr_iovecs = dm_div_up(size, PAGE_SIZE);
        int gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
-       int flags = current->flags;
-       int i;
+       unsigned long flags = current->flags;
+       unsigned int i;
 
        /*
         * Tell VM to act less aggressively and fail earlier.
@@ -280,9 +406,8 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
 static void crypt_free_buffer_pages(struct crypt_config *cc,
                                     struct bio *bio, unsigned int bytes)
 {
-       unsigned int start, end;
+       unsigned int i, start, end;
        struct bio_vec *bv;
-       int i;
 
        /*
         * This is ugly, but Jens Axboe thinks that using bi_idx in the
@@ -366,11 +491,11 @@ static void kcryptd_queue_io(struct crypt_io *io)
 /*
  * Decode key from its hex representation
  */
-static int crypt_decode_key(u8 *key, char *hex, int size)
+static int crypt_decode_key(u8 *key, char *hex, unsigned int size)
 {
        char buffer[3];
        char *endp;
-       int i;
+       unsigned int i;
 
        buffer[2] = '\0';
 
@@ -393,9 +518,9 @@ static int crypt_decode_key(u8 *key, char *hex, int size)
 /*
  * Encode key into its hex representation
  */
-static void crypt_encode_key(char *hex, u8 *key, int size)
+static void crypt_encode_key(char *hex, u8 *key, unsigned int size)
 {
-       int i;
+       unsigned int i;
 
        for(i = 0; i < size; i++) {
                sprintf(hex, "%02x", *key);
@@ -414,9 +539,11 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        struct crypto_tfm *tfm;
        char *tmp;
        char *cipher;
-       char *mode;
-       int crypto_flags;
-       int key_size;
+       char *chainmode;
+       char *ivmode;
+       char *ivopts;
+       unsigned int crypto_flags;
+       unsigned int key_size;
 
        if (argc != 5) {
                ti->error = PFX "Not enough arguments";
@@ -425,7 +552,9 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        tmp = argv[0];
        cipher = strsep(&tmp, "-");
-       mode = strsep(&tmp, "-");
+       chainmode = strsep(&tmp, "-");
+       ivopts = strsep(&tmp, "-");
+       ivmode = strsep(&ivopts, ":");
 
        if (tmp)
                DMWARN(PFX "Unexpected additional cipher options");
@@ -439,19 +568,33 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                return -ENOMEM;
        }
 
-       if (!mode || strcmp(mode, "plain") == 0)
-               cc->iv_generator = crypt_iv_plain;
-       else if (strcmp(mode, "ecb") == 0)
-               cc->iv_generator = NULL;
-       else {
-               ti->error = PFX "Invalid chaining mode";
+       cc->key_size = key_size;
+       if ((!key_size && strcmp(argv[1], "-") != 0) ||
+           (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) {
+               ti->error = PFX "Error decoding key";
                goto bad1;
        }
 
-       if (cc->iv_generator)
+       /* Compatiblity mode for old dm-crypt cipher strings */
+       if (!chainmode || (strcmp(chainmode, "plain") == 0 && !ivmode)) {
+               chainmode = "cbc";
+               ivmode = "plain";
+       }
+
+       /* Choose crypto_flags according to chainmode */
+       if (strcmp(chainmode, "cbc") == 0)
                crypto_flags = CRYPTO_TFM_MODE_CBC;
-       else
+       else if (strcmp(chainmode, "ecb") == 0)
                crypto_flags = CRYPTO_TFM_MODE_ECB;
+       else {
+               ti->error = PFX "Unknown chaining mode";
+               goto bad1;
+       }
+
+       if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) {
+               ti->error = PFX "This chaining mode requires an IV mechanism";
+               goto bad1;
+       }
 
        tfm = crypto_alloc_tfm(cipher, crypto_flags);
        if (!tfm) {
@@ -463,15 +606,39 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad2;
        }
 
+       cc->tfm = tfm;
+
+       /*
+        * Choose ivmode. Valid modes: "plain", "essiv:<esshash>".
+        * See comments at iv code
+        */
+
+       if (ivmode == NULL)
+               cc->iv_gen_ops = NULL;
+       else if (strcmp(ivmode, "plain") == 0)
+               cc->iv_gen_ops = &crypt_iv_plain_ops;
+       else if (strcmp(ivmode, "essiv") == 0)
+               cc->iv_gen_ops = &crypt_iv_essiv_ops;
+       else {
+               ti->error = PFX "Invalid IV mode";
+               goto bad2;
+       }
+
+       if (cc->iv_gen_ops && cc->iv_gen_ops->ctr &&
+           cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0)
+               goto bad2;
+
        if (tfm->crt_cipher.cit_decrypt_iv && tfm->crt_cipher.cit_encrypt_iv)
-               /* at least a 32 bit sector number should fit in our buffer */
+               /* at least a 64 bit sector number should fit in our buffer */
                cc->iv_size = max(crypto_tfm_alg_ivsize(tfm),
-                                 (unsigned int)(sizeof(u32) / sizeof(u8)));
+                                 (unsigned int)(sizeof(u64) / sizeof(u8)));
        else {
                cc->iv_size = 0;
-               if (cc->iv_generator) {
+               if (cc->iv_gen_ops) {
                        DMWARN(PFX "Selected cipher does not support IVs");
-                       cc->iv_generator = NULL;
+                       if (cc->iv_gen_ops->dtr)
+                               cc->iv_gen_ops->dtr(cc);
+                       cc->iv_gen_ops = NULL;
                }
        }
 
@@ -479,52 +646,59 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                                     mempool_free_slab, _crypt_io_pool);
        if (!cc->io_pool) {
                ti->error = PFX "Cannot allocate crypt io mempool";
-               goto bad2;
+               goto bad3;
        }
 
        cc->page_pool = mempool_create(MIN_POOL_PAGES, mempool_alloc_page,
                                       mempool_free_page, NULL);
        if (!cc->page_pool) {
                ti->error = PFX "Cannot allocate page mempool";
-               goto bad3;
-       }
-
-       cc->tfm = tfm;
-       cc->key_size = key_size;
-       if ((key_size == 0 && strcmp(argv[1], "-") != 0)
-           || crypt_decode_key(cc->key, argv[1], key_size) < 0) {
-               ti->error = PFX "Error decoding key";
                goto bad4;
        }
 
        if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) {
                ti->error = PFX "Error setting key";
-               goto bad4;
+               goto bad5;
        }
 
        if (sscanf(argv[2], SECTOR_FORMAT, &cc->iv_offset) != 1) {
                ti->error = PFX "Invalid iv_offset sector";
-               goto bad4;
+               goto bad5;
        }
 
        if (sscanf(argv[4], SECTOR_FORMAT, &cc->start) != 1) {
                ti->error = PFX "Invalid device sector";
-               goto bad4;
+               goto bad5;
        }
 
        if (dm_get_device(ti, argv[3], cc->start, ti->len,
                          dm_table_get_mode(ti->table), &cc->dev)) {
                ti->error = PFX "Device lookup failed";
-               goto bad4;
+               goto bad5;
        }
 
+       if (ivmode && cc->iv_gen_ops) {
+               if (ivopts)
+                       *(ivopts - 1) = ':';
+               cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL);
+               if (!cc->iv_mode) {
+                       ti->error = PFX "Error kmallocing iv_mode string";
+                       goto bad5;
+               }
+               strcpy(cc->iv_mode, ivmode);
+       } else
+               cc->iv_mode = NULL;
+
        ti->private = cc;
        return 0;
 
-bad4:
+bad5:
        mempool_destroy(cc->page_pool);
-bad3:
+bad4:
        mempool_destroy(cc->io_pool);
+bad3:
+       if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
+               cc->iv_gen_ops->dtr(cc);
 bad2:
        crypto_free_tfm(tfm);
 bad1:
@@ -539,6 +713,10 @@ static void crypt_dtr(struct dm_target *ti)
        mempool_destroy(cc->page_pool);
        mempool_destroy(cc->io_pool);
 
+       if (cc->iv_mode)
+               kfree(cc->iv_mode);
+       if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
+               cc->iv_gen_ops->dtr(cc);
        crypto_free_tfm(cc->tfm);
        dm_put_device(ti, cc->dev);
        kfree(cc);
@@ -577,7 +755,8 @@ static int crypt_endio(struct bio *bio, unsigned int done, int error)
 
 static inline struct bio *
 crypt_clone(struct crypt_config *cc, struct crypt_io *io, struct bio *bio,
-            sector_t sector, int *bvec_idx, struct convert_context *ctx)
+            sector_t sector, unsigned int *bvec_idx,
+            struct convert_context *ctx)
 {
        struct bio *clone;
 
@@ -630,7 +809,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
        struct bio *clone;
        unsigned int remaining = bio->bi_size;
        sector_t sector = bio->bi_sector - ti->begin;
-       int bvec_idx = 0;
+       unsigned int bvec_idx = 0;
 
        io->target = ti;
        io->bio = bio;
@@ -692,8 +871,8 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
        struct crypt_config *cc = (struct crypt_config *) ti->private;
        char buffer[32];
        const char *cipher;
-       const char *mode = NULL;
-       int offset;
+       const char *chainmode = NULL;
+       unsigned int sz = 0;
 
        switch (type) {
        case STATUSTYPE_INFO:
@@ -705,34 +884,35 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
 
                switch(cc->tfm->crt_cipher.cit_mode) {
                case CRYPTO_TFM_MODE_CBC:
-                       mode = "plain";
+                       chainmode = "cbc";
                        break;
                case CRYPTO_TFM_MODE_ECB:
-                       mode = "ecb";
+                       chainmode = "ecb";
                        break;
                default:
                        BUG();
                }
 
-               snprintf(result, maxlen, "%s-%s ", cipher, mode);
-               offset = strlen(result);
+               if (cc->iv_mode)
+                       DMEMIT("%s-%s-%s ", cipher, chainmode, cc->iv_mode);
+               else
+                       DMEMIT("%s-%s ", cipher, chainmode);
 
                if (cc->key_size > 0) {
-                       if ((maxlen - offset) < ((cc->key_size << 1) + 1))
+                       if ((maxlen - sz) < ((cc->key_size << 1) + 1))
                                return -ENOMEM;
 
-                       crypt_encode_key(result + offset, cc->key, cc->key_size);
-                       offset += cc->key_size << 1;
+                       crypt_encode_key(result + sz, cc->key, cc->key_size);
+                       sz += cc->key_size << 1;
                } else {
-                       if (offset >= maxlen)
+                       if (sz >= maxlen)
                                return -ENOMEM;
-                       result[offset++] = '-';
+                       result[sz++] = '-';
                }
 
                format_dev_t(buffer, cc->dev->bdev->bd_dev);
-               snprintf(result + offset, maxlen - offset, " " SECTOR_FORMAT
-                        " %s " SECTOR_FORMAT, cc->iv_offset,
-                        buffer, cc->start);
+               DMEMIT(" " SECTOR_FORMAT " %s " SECTOR_FORMAT,
+                      cc->iv_offset, buffer, cc->start);
                break;
        }
        return 0;
@@ -740,7 +920,7 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
 
 static struct target_type crypt_target = {
        .name   = "crypt",
-       .version= {1, 0, 0},
+       .version= {1, 1, 0},
        .module = THIS_MODULE,
        .ctr    = crypt_ctr,
        .dtr    = crypt_dtr,
index 9f3fb61..cb7a43f 100644 (file)
@@ -267,7 +267,7 @@ static int resize_pool(unsigned int new_ios)
                /* create new pool */
                _io_pool = mempool_create(new_ios, alloc_io, free_io, NULL);
                if (!_io_pool)
-                       r = -ENOMEM;
+                       return -ENOMEM;
 
                r = bio_set_init(&_bios, "dm-io", 512, 1);
                if (r) {
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 */
index ae45ae9..e7d934e 100644 (file)
@@ -48,18 +48,14 @@ static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk,
        mdk_rdev_t **devlist = conf->strip_zone[0].dev;
        int i, ret = 0;
 
-       for (i=0; i<mddev->raid_disks; i++) {
+       for (i=0; i<mddev->raid_disks && ret == 0; i++) {
                struct block_device *bdev = devlist[i]->bdev;
                request_queue_t *r_queue = bdev_get_queue(bdev);
 
-               if (!r_queue->issue_flush_fn) {
+               if (!r_queue->issue_flush_fn)
                        ret = -EOPNOTSUPP;
-                       break;
-               }
-
-               ret =r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
-               if (ret)
-                       break;
+               else
+                       ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
        }
        return ret;
 }
@@ -389,6 +385,7 @@ static int raid0_stop (mddev_t *mddev)
 {
        raid0_conf_t *conf = mddev_to_conf(mddev);
 
+       blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
        kfree (conf->hash_table);
        conf->hash_table = NULL;
        kfree (conf->strip_zone);
index 79d29ef..508cc05 100644 (file)
@@ -34,27 +34,18 @@ source "drivers/media/common/Kconfig"
 
 config VIDEO_TUNER
        tristate
-       default y if VIDEO_BT848=y || VIDEO_SAA7134=y || VIDEO_MXB=y || VIDEO_CX88=y
-       default m if VIDEO_BT848=m || VIDEO_SAA7134=m || VIDEO_MXB=m || VIDEO_CX88=m
-       depends on VIDEO_DEV
 
 config VIDEO_BUF
        tristate
-       default y if VIDEO_BT848=y || VIDEO_SAA7134=y || VIDEO_SAA7146=y || VIDEO_CX88=y
-       default m if VIDEO_BT848=m || VIDEO_SAA7134=m || VIDEO_SAA7146=m || VIDEO_CX88=m
-       depends on VIDEO_DEV
+
+config VIDEO_BUF_DVB
+       tristate
 
 config VIDEO_BTCX
        tristate
-       default y if VIDEO_BT848=y || VIDEO_CX88=y
-       default m if VIDEO_BT848=m || VIDEO_CX88=m
-       depends on VIDEO_DEV
 
 config VIDEO_IR
        tristate
-       default y if VIDEO_BT848=y || VIDEO_SAA7134=y
-       default m if VIDEO_BT848=m || VIDEO_SAA7134=m
-       depends on VIDEO_DEV
 
 endmenu
 
index 369d949..5c3a549 100644 (file)
@@ -25,11 +25,11 @@ struct list_head saa7146_devices;
 struct semaphore saa7146_devices_lock;
 
 static int initialized = 0;
-int saa7146_num = 0;
+static int saa7146_num = 0;
 
 unsigned int saa7146_debug = 0;
 
-MODULE_PARM(saa7146_debug,"i");
+module_param(saa7146_debug, int, 0644);
 MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
 
 #if 0
@@ -48,7 +48,7 @@ static void dump_registers(struct saa7146_dev* dev)
  * gpio and debi helper functions
  ****************************************************************************/
 
-/* write "data" to the gpio-pin "pin" */
+/* write "data" to the gpio-pin "pin" -- unused */
 void saa7146_set_gpio(struct saa7146_dev *dev, u8 pin, u8 data)
 {
        u32 value = 0;
@@ -67,7 +67,7 @@ void saa7146_set_gpio(struct saa7146_dev *dev, u8 pin, u8 data)
 }
 
 /* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
-int saa7146_wait_for_debi_done(struct saa7146_dev *dev)
+int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
 {
        unsigned long start;
 
@@ -80,6 +80,8 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev)
                        DEB_S(("timed out while waiting for registers getting programmed\n"));
                        return -ETIMEDOUT;
                }
+               if (nobusyloop)
+                       msleep(1);
        }
 
        /* wait for transfer to complete */
@@ -92,6 +94,8 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev)
                        DEB_S(("timed out while waiting for transfer completion\n"));
                        return -ETIMEDOUT;
                }
+               if (nobusyloop)
+                       msleep(1);
        }
 
        return 0;
@@ -133,8 +137,6 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
 /********************************************************************************/
 /* common page table functions */
 
-#define SAA7146_PGTABLE_SIZE 4096
-
 char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
 {
        int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
@@ -182,11 +184,11 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
         u32          *cpu;
         dma_addr_t   dma_addr;
 
-       cpu = pci_alloc_consistent(pci, SAA7146_PGTABLE_SIZE, &dma_addr);
+       cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
        if (NULL == cpu) {
                return -ENOMEM;
        }
-       pt->size = SAA7146_PGTABLE_SIZE;
+       pt->size = PAGE_SIZE;
        pt->cpu  = cpu;
        pt->dma  = dma_addr;
 
@@ -201,11 +203,7 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
        int   i,p;
 
        BUG_ON( 0 == sglen);
-
-       if (list->offset > PAGE_SIZE) {
-               DEB_D(("offset > PAGE_SIZE. this should not happen."));
-               return -EINVAL;
-       }
+       BUG_ON(list->offset > PAGE_SIZE);
        
        /* if we have a user buffer, the first page may not be
           aligned to a page boundary. */
@@ -217,7 +215,7 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
                printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset);
 */
                for (p = 0; p * 4096 < list->length; p++, ptr++) {
-                       *ptr = sg_dma_address(list) + p * 4096;
+                       *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
                        nr_pages++;
                }
        }
@@ -254,10 +252,9 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
 
 /********************************************************************************/
 /* interrupt handler */
-
 static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
 {
-       struct saa7146_dev *dev = (struct saa7146_dev*)dev_id;
+       struct saa7146_dev *dev = dev_id;
        u32 isr = 0;
 
        /* read out the interrupt status register */
@@ -295,7 +292,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
        if (0 != (isr & (MASK_16|MASK_17))) {
                u32 status = saa7146_read(dev, I2C_STATUS);
                if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) {
-                       IER_DISABLE(dev, MASK_16|MASK_17);
+                       SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
                        /* only wake up if we expect something */
                        if( 0 != dev->i2c_op ) {
                                u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2;
@@ -314,7 +311,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
        if( 0 != isr ) {
                ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr));
                ERR(("disabling interrupt source(s)!\n"));
-               IER_DISABLE(dev,isr);
+               SAA7146_IER_DISABLE(dev,isr);
        }
        return IRQ_HANDLED;
 }
@@ -324,16 +321,15 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
 
 static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
 {
-       unsigned long adr = 0, len = 0;
-       struct saa7146_dev* dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL);
-       
        struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
        struct saa7146_extension* ext = pci_ext->ext;
-       int err = 0;
+       struct saa7146_dev *dev;
+       int err = -ENOMEM;
        
-       if (!(dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL))) {
+       dev = kmalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
+       if (!dev) {
                ERR(("out of memory.\n"));
-               return -ENOMEM;
+               goto out;
        }
 
        /* clear out mem for sure */
@@ -341,38 +337,37 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
 
        DEB_EE(("pci:%p\n",pci));
 
-       if (pci_enable_device(pci)) {
+       err = pci_enable_device(pci);
+       if (err < 0) {
                ERR(("pci_enable_device() failed.\n"));
-               err = -EIO;
-               goto pci_error;
+               goto err_free;
        }
 
        /* enable bus-mastering */
        pci_set_master(pci);
 
        dev->pci = pci;
+
        /* get chip-revision; this is needed to enable bug-fixes */
-       if( 0 > pci_read_config_dword(dev->pci, PCI_CLASS_REVISION, &dev->revision)) {
+       err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision);
+       if (err < 0) {
                ERR(("pci_read_config_dword() failed.\n"));
-               err = -ENODEV;
-               goto pci_error;
+               goto err_disable;
        }
        dev->revision &= 0xf;
 
        /* remap the memory from virtual to physical adress */
-       adr = pci_resource_start(pci,0);
-       len = pci_resource_len(pci,0);
 
-       if (!request_mem_region(pci_resource_start(pci,0), pci_resource_len(pci,0), "saa7146")) {
-               ERR(("request_mem_region() failed.\n"));
-               err = -ENODEV;
-               goto pci_error;
-       }
+       err = pci_request_region(pci, 0, "saa7146");
+       if (err < 0)
+               goto err_disable;
 
-       if (!(dev->mem = ioremap(adr,len))) {
+       dev->mem = ioremap(pci_resource_start(pci, 0),
+                          pci_resource_len(pci, 0));
+       if (!dev->mem) {
                ERR(("ioremap() failed.\n"));
                err = -ENODEV;
-               goto ioremap_error;
+               goto err_release;
        }
 
        /* we don't do a master reset here anymore, it screws up
@@ -392,42 +387,40 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        saa7146_write(dev, MC2, 0xf8000000);
 
        /* request an interrupt for the saa7146 */
-       if (request_irq(dev->pci->irq, interrupt_hw, SA_SHIRQ | SA_INTERRUPT,
-                       dev->name, dev))
-       {
+       err = request_irq(pci->irq, interrupt_hw, SA_SHIRQ | SA_INTERRUPT,
+                         dev->name, dev);
+       if (err < 0) {
                ERR(("request_irq() failed.\n"));
-               err = -ENODEV;
-               goto irq_error;
+               goto err_unmap;
        }
 
-       /* get memory for various stuff */
-       dev->d_rps0.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_rps0.dma_handle);        
-       if( NULL == dev->d_rps0.cpu_addr ) {
                err = -ENOMEM;
-               goto kmalloc_error_1;
-       }
+
+       /* get memory for various stuff */
+       dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+                                                   &dev->d_rps0.dma_handle);
+       if (!dev->d_rps0.cpu_addr)
+               goto err_free_irq;
        memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM);
 
-       dev->d_rps1.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_rps1.dma_handle);        
-       if( NULL == dev->d_rps1.cpu_addr ) {
-               err = -ENOMEM;
-               goto kmalloc_error_2;
-       }
+       dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+                                                   &dev->d_rps1.dma_handle);
+       if (!dev->d_rps1.cpu_addr)
+               goto err_free_rps0;
        memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM);
 
-       dev->d_i2c.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_i2c.dma_handle);  
-       if( NULL == dev->d_i2c.cpu_addr ) {
-               err = -ENOMEM;
-               goto kmalloc_error_3;
-       }
+       dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+                                                  &dev->d_i2c.dma_handle);
+       if (!dev->d_i2c.cpu_addr)
+               goto err_free_rps1;
        memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM);
 
        /* the rest + print status message */
 
        /* create a nice device name */
-       sprintf(&dev->name[0], "saa7146 (%d)",saa7146_num);
+       sprintf(dev->name, "saa7146 (%d)", saa7146_num);
 
-       INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision,dev->pci->irq,dev->pci->subsystem_vendor,dev->pci->subsystem_device));
+       INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
        dev->ext = ext;
 
        pci_set_drvdata(pci,dev);
@@ -444,18 +437,18 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        /* set some sane pci arbitrition values */
        saa7146_write(dev, PCI_BT_V1, 0x1c00101f); 
 
-       if( 0 != ext->probe) {
-               if( 0 != ext->probe(dev) ) {
-                       DEB_D(("ext->probe() failed for %p. skipping device.\n",dev));
+       /* TODO: use the status code of the callback */
+
                        err = -ENODEV;
-                       goto probe_error;
-               }
+
+       if (ext->probe && ext->probe(dev)) {
+               DEB_D(("ext->probe() failed for %p. skipping device.\n",dev));
+               goto err_free_i2c;
        }
 
-       if( 0 != ext->attach(dev,pci_ext) ) {
+       if (ext->attach(dev, pci_ext)) {
                DEB_D(("ext->attach() failed for %p. skipping device.\n",dev));
-                       err = -ENODEV;
-                       goto attach_error;
+               goto err_unprobe;
        }
 
        INIT_LIST_HEAD(&dev->item);
@@ -463,30 +456,46 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        saa7146_num++;
 
        err = 0;
-       goto out;
-attach_error:
-probe_error:
+out:
+       return err;
+
+err_unprobe:
        pci_set_drvdata(pci,NULL);
-       pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle);
-kmalloc_error_3:
-       pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle);
-kmalloc_error_2:
-       pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle);
-kmalloc_error_1:
-       free_irq(dev->pci->irq, (void *)dev);
-irq_error:
+err_free_i2c:
+       pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
+                           dev->d_i2c.dma_handle);
+err_free_rps1:
+       pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,
+                           dev->d_rps1.dma_handle);
+err_free_rps0:
+       pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,
+                           dev->d_rps0.dma_handle);
+err_free_irq:
+       free_irq(pci->irq, (void *)dev);
+err_unmap:
        iounmap(dev->mem);
-ioremap_error:
-        release_mem_region(adr,len);
-pci_error:
+err_release:
+       pci_release_region(pci, 0);
+err_disable:
+       pci_disable_device(pci);
+err_free:
        kfree(dev);
-out:
-       return err;
+       goto out;
 }
 
 static void saa7146_remove_one(struct pci_dev *pdev)
 {
-       struct saa7146_dev* dev = (struct saa7146_dev*) pci_get_drvdata(pdev);
+       struct saa7146_dev* dev = pci_get_drvdata(pdev);
+       struct {
+               void *addr;
+               dma_addr_t dma;
+       } dev_map[] = {
+               { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },
+               { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },
+               { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },
+               { NULL, 0 }
+       }, *p;
+
        DEB_EE(("dev:%p\n",dev));
 
        dev->ext->detach(dev);
@@ -497,17 +506,15 @@ static void saa7146_remove_one(struct pci_dev *pdev)
        /* disable all irqs, release irq-routine */
        saa7146_write(dev, IER, 0);
 
-       free_irq(dev->pci->irq, (void *)dev);
+       free_irq(pdev->irq, dev);
 
-       /* free kernel memory */
-       pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle);
-       pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle);
-       pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle);
+       for (p = dev_map; p->addr; p++)
+               pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);
 
        iounmap(dev->mem);
-       release_mem_region(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0));
-
+       pci_release_region(pdev, 0);
        list_del(&dev->item);
+       pci_disable_device(pdev);
        kfree(dev);
 
        saa7146_num--;
index bdae7fa..7bf6316 100644 (file)
@@ -9,11 +9,6 @@ static void calculate_output_format_register(struct saa7146_dev* saa, u32 palett
        *clip_format |=  (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16));
 }
 
-static void calculate_bcs_ctrl_register(struct saa7146_dev *dev, int brightness, int contrast, int colour, u32 *bcs_ctrl)
-{
-       *bcs_ctrl = ((brightness << 24) | (contrast << 16) | (colour <<  0));
-}
-
 static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl)
 {
        *hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28);
@@ -62,7 +57,7 @@ static struct {
 };
 
 /* table of attenuation values for horizontal scaling */
-u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0};
+static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0};
 
 /* calculate horizontal scale registers */
 static int calculate_h_scale_registers(struct saa7146_dev *dev,
@@ -208,7 +203,7 @@ static struct {
 };
 
 /* table of attenuation values for vertical scaling */
-u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0};
+static u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0};
 
 /* calculate vertical scale registers */
 static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field,
@@ -413,10 +408,10 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa
 
        /* fill up cliptable */
        for(i = 0; i < cnt_pixel; i++) {
-               clipping[2*i] |= (pixel_list[i] << 16);
+               clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16);
        }
        for(i = 0; i < cnt_line; i++) {
-               clipping[(2*i)+1] |= (line_list[i] << 16);
+               clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16);
        }
 
        /* fill up cliptable with the display infos */
@@ -430,7 +425,7 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa
                        if( pixel_list[i] < (x[j] + w[j])) {
                        
                                if ( pixel_list[i] >= x[j] ) {
-                                       clipping[2*i] |= (1 << j);                      
+                                       clipping[2*i] |= cpu_to_le32(1 << j);
                                }
                        }
                }
@@ -442,7 +437,7 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa
                        if( line_list[i] < (y[j] + h[j]) ) {
 
                                if( line_list[i] >= y[j] ) {
-                                       clipping[(2*i)+1] |= (1 << j);                  
+                                       clipping[(2*i)+1] |= cpu_to_le32(1 << j);
                                }
                        }
                }
@@ -560,9 +555,10 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e
 }
 
 /* calculate the new memory offsets for a desired position */
-static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field)
+static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
 {      
        struct saa7146_vv *vv = dev->vv_data;
+       struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat);
 
        int b_depth = vv->ov_fmt->depth;
        int b_bpl = vv->ov_fb.fmt.bytesperline;
@@ -601,7 +597,7 @@ static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int
                vdma1.pitch *= -1;
        }
                
-       vdma1.base_page = 0;
+       vdma1.base_page = sfmt->swap;
        vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels;
 
        saa7146_write_out_dma(dev, 1, &vdma1);
@@ -619,18 +615,6 @@ static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long pal
        saa7146_write(dev, MC2, (MASK_05 | MASK_21));
 }
 
-void saa7146_set_picture_prop(struct saa7146_dev *dev, int brightness, int contrast, int colour)
-{
-       u32     bcs_ctrl = 0;
-       
-       calculate_bcs_ctrl_register(dev, brightness, contrast, colour, &bcs_ctrl);
-       saa7146_write(dev, BCS_CTRL, bcs_ctrl);
-       
-       /* update the bcs register */
-       saa7146_write(dev, MC2, (MASK_06 | MASK_22));
-}
-
-
 /* select input-source */
 void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync)
 {
@@ -657,7 +641,7 @@ int saa7146_enable_overlay(struct saa7146_fh *fh)
        struct saa7146_vv *vv = dev->vv_data;
 
        saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field);
-       saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field);
+       saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field, vv->ov_fmt->pixelformat);
        saa7146_set_output_format(dev, vv->ov_fmt->trans);
        saa7146_set_clipping_rect(fh);
 
@@ -727,7 +711,7 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71
        vdma1.pitch             = (width*depth*2)/8;
        }
        vdma1.num_line_byte     = ((vv->standard->v_field<<16) + vv->standard->h_pixels);
-       vdma1.base_page         = buf->pt[0].dma | ME1;
+       vdma1.base_page         = buf->pt[0].dma | ME1 | sfmt->swap;
        
        if( 0 != vv->vflip ) {
                vdma1.prot_addr = buf->pt[0].offset;
index 118cace..875ebd4 100644 (file)
@@ -1,7 +1,7 @@
 #include <linux/version.h>
 #include <media/saa7146_vv.h>
 
-u32 saa7146_i2c_func(struct i2c_adapter *adapter)
+static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
 {
 //fm   DEB_I2C(("'%s'.\n", adapter->name));
 
@@ -190,7 +190,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
                saa7146_write(dev, I2C_TRANSFER, *dword);
 
                dev->i2c_op = 1;
-               IER_ENABLE(dev, MASK_16|MASK_17);
+               SAA7146_IER_ENABLE(dev, MASK_16|MASK_17);
                saa7146_write(dev, MC2, (MASK_00 | MASK_16));
 
                wait_event_interruptible(dev->i2c_wq, dev->i2c_op == 0);
@@ -393,7 +393,7 @@ static struct i2c_algorithm saa7146_algo = {
        .functionality  = saa7146_i2c_func,
 };
 
-int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, unsigned int class, u32 bitrate)
+int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
 {
        DEB_EE(("bitrate: 0x%08x\n",bitrate));
        
@@ -404,13 +404,11 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
        saa7146_i2c_reset(dev);
 
        if( NULL != i2c_adapter ) {
-               memset(i2c_adapter,0,sizeof(struct i2c_adapter));
-               strcpy(i2c_adapter->name, dev->name);   
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
                i2c_adapter->data = dev;
 #else
+               BUG_ON(!i2c_adapter->class);
                i2c_set_adapdata(i2c_adapter,dev);
-               i2c_adapter->class = class;
 #endif
                i2c_adapter->algo          = &saa7146_algo;
                i2c_adapter->algo_data     = NULL;
index f0f1520..c9a5138 100644 (file)
@@ -12,26 +12,15 @@ config DVB
          own a DVB adapter and want to use it or if you compile Linux for 
          a digital SetTopBox.
 
-         API specs and user tools are available from
-         <http://www.linuxtv.org/>. 
+         API specs and user tools are available from <http://www.linuxtv.org/>.
 
          Please report problems regarding this driver to the LinuxDVB 
          mailing list.
 
-         You might want add the following lines to your /etc/modules.conf:
-               
-               alias char-major-250 dvb
-               alias dvb dvb-ttpci
-               below dvb-ttpci alps_bsru6 alps_bsrv2 \
-                               grundig_29504-401 grundig_29504-491 \
-                               ves1820
-
          If unsure say N.
 
 source "drivers/media/dvb/dvb-core/Kconfig"
 
-source "drivers/media/dvb/frontends/Kconfig"
-
 comment "Supported SAA7146 based PCI Adapters"
        depends on DVB_CORE && PCI
 source "drivers/media/dvb/ttpci/Kconfig"
@@ -40,6 +29,8 @@ comment "Supported USB Adapters"
        depends on DVB_CORE && USB
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
+source "drivers/media/dvb/dibusb/Kconfig"
+source "drivers/media/dvb/cinergyT2/Kconfig"
 
 comment "Supported FlexCopII (B2C2) Adapters"
        depends on DVB_CORE && PCI
@@ -49,5 +40,8 @@ comment "Supported BT878 Adapters"
        depends on DVB_CORE && PCI
 source "drivers/media/dvb/bt8xx/Kconfig"
 
-endmenu
+comment "Supported DVB Frontends"
+       depends on DVB_CORE
+source "drivers/media/dvb/frontends/Kconfig"
 
+endmenu
index 2263ebf..520fc39 100644 (file)
@@ -2,5 +2,4 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/
-
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dibusb/ cinergyT2/
index b3a45b4..354f9df 100644 (file)
@@ -1,8 +1,24 @@
 config DVB_B2C2_SKYSTAR
-       tristate "Technisat Skystar2 PCI"
+       tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI"
        depends on DVB_CORE && PCI
+       select DVB_STV0299
+       select DVB_MT352
+       select DVB_MT312
        help
          Support for the Skystar2 PCI DVB card by Technisat, which
          is equipped with the FlexCopII chipset by B2C2.
 
          Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_USB
+       tristate "B2C2/Technisat Air/Sky/Cable2PC USB"
+       depends on DVB_CORE && USB && EXPERIMENTAL
+       select DVB_STV0299
+       select DVB_MT352
+       help
+         Support for the Air/Sky/Cable2PC USB DVB device by B2C2. Currently
+         this does nothing, but providing basic function for the used usb
+         protocol.
+
+         Say Y if you own such a device and want to use it.
+
index df86d99..9fb1247 100644 (file)
@@ -1,3 +1,6 @@
+obj-b2c2-usb = b2c2-usb-core.o b2c2-common.o
+
 obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o
+obj-$(CONFIG_DVB_B2C2_USB) + = b2c2-usb.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
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");
index 572bd49..114787f 100644 (file)
@@ -1,13 +1,18 @@
 config DVB_BT8XX
-       tristate "Nebula/Pinnacle PCTV PCI cards"
+       tristate "Nebula/Pinnacle PCTV/Twinhan PCI cards"
        depends on DVB_CORE && PCI && VIDEO_BT848
+       select DVB_MT352
+       select DVB_SP887X
        help
          Support for PCI cards based on the Bt8xx PCI bridge. Examples are
-         the Nebula cards, the Pinnacle PCTV cards, and Twinhan DST cards.
+         the Nebula cards, the Pinnacle PCTV cards and Twinhan DST cards.
 
           Since these cards have no MPEG decoder onboard, they transmit
          only compressed MPEG data over the PCI bus, so you need
          an external software decoder to watch TV on your computer.
 
+         If you have a Twinhan card, don't forget to select
+         "Twinhan DST based DVB-S/-T frontend".
+
          Say Y if you own such a device and want to use it.
 
index 6db2890..9da8604 100644 (file)
@@ -1,5 +1,5 @@
 
-obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o
+obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o
 
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video -Idrivers/media/dvb/frontends
 
index 7f7ec33..7968bfe 100644 (file)
@@ -27,8 +27,8 @@
  * 
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <asm/io.h>
 #include "dmxdev.h"
 #include "dvbdev.h"
 #include "bt878.h"
-#include "dst-bt878.h"
+#include "dst_priv.h"
 
-#include "dvb_functions.h"
 
 /**************************************/
 /* Miscellaneous utility  definitions */
 /**************************************/
 
-unsigned int bt878_verbose = 1;
-unsigned int bt878_debug = 0;
-MODULE_PARM(bt878_verbose, "i");
+static unsigned int bt878_verbose = 1;
+static unsigned int bt878_debug;
+
+module_param_named(verbose, bt878_verbose, int, 0444);
 MODULE_PARM_DESC(bt878_verbose,
                 "verbose startup messages, default is 1 (yes)");
-MODULE_PARM(bt878_debug, "i");
-MODULE_PARM_DESC(bt878_debug, "debug messages, default is 0 (no)");
-MODULE_LICENSE("GPL");
+module_param_named(debug, bt878_debug, int, 0644);
+MODULE_PARM_DESC(bt878_debug, "Turn on/off debugging (default:off).");
 
 int bt878_num;
 struct bt878 bt878[BT878_MAX];
@@ -339,10 +338,6 @@ static irqreturn_t bt878_irq(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-extern int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data);
-extern int bttv_read_gpio(unsigned int card, unsigned long *data);
-extern int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data);
-
 int
 bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp)
 {
@@ -386,20 +381,20 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
 
 EXPORT_SYMBOL(bt878_device_control);
 
-struct bt878 *bt878_find_by_dvb_adap(struct dvb_adapter *adap)
+struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adapter)
 {
        unsigned int card_nr;
        
-       printk("bt878 find by dvb adap: checking \"%s\"\n",adap->name);
+       printk("bt878 find by dvb adap: checking \"%s\"\n",adapter->name);
        for (card_nr = 0; card_nr < bt878_num; card_nr++) {
-               if (bt878[card_nr].adap_ptr == adap)
+               if (bt878[card_nr].adapter == adapter)
                        return &bt878[card_nr];
        }
-       printk("bt878 find by dvb adap: NOT found \"%s\"\n",adap->name);
+       printk("bt878 find by dvb adap: NOT found \"%s\"\n",adapter->name);
        return NULL;
 }
 
-EXPORT_SYMBOL(bt878_find_by_dvb_adap);
+EXPORT_SYMBOL(bt878_find_by_i2c_adap);
 
 /***********************/
 /* PCI device handling */
@@ -516,7 +511,7 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev)
                printk("bt878(%d): unloading\n", bt->nr);
 
        /* turn off all capturing, DMA and IRQs */
-       btand(~13, BT878_AGPIO_DMA_CTL);
+       btand(~0x13, BT878_AGPIO_DMA_CTL);
 
        /* first disable interrupts before unmapping the memory! */
        btwrite(0, BT878_AINT_MASK);
@@ -564,22 +559,11 @@ static struct pci_driver bt878_pci_driver = {
 
 static int bt878_pci_driver_registered = 0;
 
-/* This will be used later by dvb-bt8xx to only use the audio
- * dma of certain cards */
-int bt878_find_audio_dma(void)
-{
-       // pci_register_driver(&bt878_pci_driver);
-       bt878_pci_driver_registered = 1;
-       return 0;
-}
-
-EXPORT_SYMBOL(bt878_find_audio_dma);
-
 /*******************************/
 /* Module management functions */
 /*******************************/
 
-int bt878_init_module(void)
+static int bt878_init_module(void)
 {
        bt878_num = 0;
        bt878_pci_driver_registered = 0;
@@ -591,13 +575,13 @@ int bt878_init_module(void)
 /*
         bt878_check_chipset();
 */
-       /* later we register inside of bt878_find_audio_dma
+       /* later we register inside of bt878_find_audio_dma()
         * because we may want to ignore certain cards */
        bt878_pci_driver_registered = 1;
        return pci_module_init(&bt878_pci_driver);
 }
 
-void bt878_cleanup_module(void)
+static void bt878_cleanup_module(void)
 {
        if (bt878_pci_driver_registered) {
                bt878_pci_driver_registered = 0;
@@ -606,11 +590,12 @@ void bt878_cleanup_module(void)
        return;
 }
 
-EXPORT_SYMBOL(bt878_init_module);
-EXPORT_SYMBOL(bt878_cleanup_module);
 module_init(bt878_init_module);
 module_exit(bt878_cleanup_module);
 
+//MODULE_AUTHOR("XXX");
+MODULE_LICENSE("GPL");
+
 /*
  * Local variables:
  * c-basic-offset: 8
index ebffd12..22fa521 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include "bt848.h"
+#include "bttv.h"
 
 #define BT878_VERSION_CODE 0x000000
 
@@ -94,14 +95,14 @@ struct bt878 {
        struct semaphore  gpio_lock;
        unsigned int nr;
        unsigned int bttv_nr;
-       struct dvb_adapter *adap_ptr;
+       struct i2c_adapter *adapter;
        struct pci_dev *dev;
        unsigned int id;
        unsigned int TS_Size;
        unsigned char revision;
        unsigned int irq;
        unsigned long bt878_adr;
-       unsigned char *bt878_mem; /* function 1 */
+       volatile void __iomem *bt878_mem; /* function 1 */
 
        volatile u32 finished_block;
        volatile u32 last_block;
@@ -128,17 +129,17 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
 void bt878_stop(struct bt878 *bt);          
 
 #if defined(__powerpc__)       /* big-endian */
-extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
+extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
 {
        __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val),
                             "r"(addr));
        __asm__ __volatile__("eieio":::"memory");
 }
 
-#define bmtwrite(dat,adr)  io_st_le32((unsigned *)(adr),(dat))
-#define bmtread(adr)       ld_le32((unsigned *)(adr))
+#define bmtwrite(dat,adr)  io_st_le32((adr),(dat))
+#define bmtread(adr)       ld_le32((adr))
 #else
-#define bmtwrite(dat,adr)  writel((dat), (char *) (adr))
+#define bmtwrite(dat,adr)  writel((dat), (adr))
 #define bmtread(adr)       readl(adr)
 #endif
 
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);
index 969606e..f25a251 100644 (file)
 #include <linux/i2c.h>
 #include "dvbdev.h"
 #include "dvb_net.h"
+#include "bttv.h"
+#include "mt352.h"
+#include "sp887x.h"
+#include "dst.h"
+#include "nxt6000.h"
 
 struct dvb_bt8xx_card {
-
-       struct list_head list;
-       u8 active;
+       struct semaphore lock;
+       int nfeeds;
        char card_name[32];
        struct dvb_adapter *dvb_adapter;
        struct bt878 *bt;
@@ -44,4 +48,5 @@ struct dvb_bt8xx_card {
        struct i2c_adapter *i2c_adapter;
        struct dvb_net dvbnet;
                                
+       struct dvb_frontend* fe;
 };
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
index 7127789..c6baac2 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
-               dvb_ca_en50221.o dvb_functions.o dvb_frontend.o \
-               dvb_i2c.o dvb_net.o dvb_ksyms.o dvb_ringbuffer.o
+               dvb_ca_en50221.o dvb_frontend.o \
+               dvb_net.o dvb_ringbuffer.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
index 8458f7a..8467e63 100644 (file)
 /* Structure describing a CA interface */
 struct dvb_ca_en50221 {
 
+       /* the module owning this structure */
+       struct module* owner;
+
+       /* NOTE: the read_*, write_* and poll_slot_status functions must use locks as
+        * they may be called from several threads at once */
+
        /* functions for accessing attribute memory on the CAM */
        int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
        int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
@@ -59,7 +65,7 @@ struct dvb_ca_en50221 {
        * Poll slot status.
        * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
        */
-       int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot);
+       int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open);
 
        /* private data, used by caller */
        void* data;
index 829c438..5ce4f65 100644 (file)
@@ -3,19 +3,20 @@
 #include <linux/string.h>
 #include "dvb_filter.h"
 
-unsigned int bitrates[3][16] =
+#if 0
+static unsigned int bitrates[3][16] =
 {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
  {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
  {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
+#endif
 
-u32 freq[4] = {441, 480, 320, 0};
+static u32 freq[4] = {480, 441, 320, 0};
 
-unsigned int ac3_bitrates[32] =
+static unsigned int ac3_bitrates[32] =
     {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
      0,0,0,0,0,0,0,0,0,0,0,0,0};
 
-u32 ac3_freq[4] = {480, 441, 320, 0};
-u32 ac3_frames[3][32] =
+static u32 ac3_frames[3][32] =
     {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
       1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
      {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
@@ -389,6 +390,7 @@ int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int p
 
        return 0;
 }
+EXPORT_SYMBOL(dvb_filter_get_ac3info);
 
 
 #if 0
@@ -563,6 +565,7 @@ void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
        p2ts->cb=cb;
        p2ts->priv=priv;
 }
+EXPORT_SYMBOL(dvb_filter_pes2ts_init);
 
 int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
                      int len, int payload_start)
@@ -597,4 +600,5 @@ int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
        memcpy(buf+5+rest, pes, len);
        return p2ts->cb(p2ts->priv, buf);
 }
+EXPORT_SYMBOL(dvb_filter_pes2ts);
 
index 94d6cfa..1511608 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * dvb-core.c: DVB core driver
+ * dvb_frontend.c: DVB frontend tuning interface/thread
+ *
  *
  * Copyright (C) 1999-2001 Ralph  Metzler
  *                         Marcus Metzler
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/list.h>
+#include <linux/suspend.h>
 #include <asm/processor.h>
 #include <asm/semaphore.h>
 
 #include "dvb_frontend.h"
 #include "dvbdev.h"
-#include "dvb_functions.h"
+
+static int dvb_frontend_debug;
+static int dvb_shutdown_timeout = 5;
+static int dvb_force_auto_inversion;
+static int dvb_override_tune_delay;
+static int dvb_powerdown_on_sleep = 1;
+
+module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
+MODULE_PARM_DESC(dvb_frontend_debug, "Turn on/off frontend core debugging (default:off).");
+module_param(dvb_shutdown_timeout, int, 0444);
+MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
+module_param(dvb_force_auto_inversion, int, 0444);
+MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
+module_param(dvb_override_tune_delay, int, 0444);
+MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
+module_param(dvb_powerdown_on_sleep, int, 0444);
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
+
+#define dprintk if (dvb_frontend_debug) printk
 
 #define FESTATE_IDLE 1
 #define FESTATE_RETUNE 2
  * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
  */
 
-
-static int dvb_frontend_debug = 0;
-static int dvb_shutdown_timeout = 5;
-static int dvb_override_frequency_bending = 0;
-static int dvb_force_auto_inversion = 0;
-static int dvb_override_tune_delay = 0;
-
-static int do_frequency_bending = 0;
-
-#define dprintk if (dvb_frontend_debug) printk
-
-#define MAX_EVENT 8
-
-struct dvb_fe_events {
-       struct dvb_frontend_event events[MAX_EVENT];
-       int                       eventw;
-       int                       eventr;
-       int                       overflow;
-       wait_queue_head_t         wait_queue;
-       struct semaphore          sem;
-};
-
-
-struct dvb_frontend_data {
-       struct dvb_frontend_info *info;
-       struct dvb_frontend frontend;
-       struct dvb_device *dvbdev;
-       struct dvb_frontend_parameters parameters;
-       struct dvb_fe_events events;
-       struct semaphore sem;
-       struct list_head list_head;
-       wait_queue_head_t wait_queue;
-       pid_t thread_pid;
-       unsigned long release_jiffies;
-       int state;
-       int bending;
-       int lnb_drift;
-       int inversion;
-       int auto_step;
-       int auto_sub_step;
-       int started_auto_step;
-       int min_delay;
-       int max_drift;
-       int step_size;
-       int exit;
-       int wakeup;
-        fe_status_t status;
-};
-
-
-struct dvb_frontend_ioctl_data {
-       struct list_head list_head;
-       struct dvb_adapter *adapter;
-       int (*before_ioctl) (struct dvb_frontend *frontend,
-                            unsigned int cmd, void *arg);
-       int (*after_ioctl)  (struct dvb_frontend *frontend,
-                            unsigned int cmd, void *arg);
-       void *before_after_data;
-};
-
-
-struct dvb_frontend_notifier_data {
-       struct list_head list_head;
-       struct dvb_adapter *adapter;
-       void (*callback) (fe_status_t s, void *data);
-       void *data;
-};
-
-
-static LIST_HEAD(frontend_list);
-static LIST_HEAD(frontend_ioctl_list);
-static LIST_HEAD(frontend_notifier_list);
-
 static DECLARE_MUTEX(frontend_mutex);
 
-
-static int dvb_frontend_internal_ioctl (struct dvb_frontend *frontend, 
-                                unsigned int cmd, void *arg)
-{
-       int err = -EOPNOTSUPP;
-
-       dprintk ("%s\n", __FUNCTION__);
-
-       if (frontend->before_ioctl)
-               err = frontend->before_ioctl (frontend, cmd, arg);
-
-       if (err == -EOPNOTSUPP) {
-               err = frontend->ioctl (frontend, cmd, arg);
-
-               if ((err == -EOPNOTSUPP) && frontend->after_ioctl)
-                       err = frontend->after_ioctl (frontend, cmd, arg);
-       }
-
-       return err;
-}
-
-
-/**
- *  if 2 tuners are located side by side you can get interferences when
- *  they try to tune to the same frequency, so both lose sync.
- *  We will slightly mistune in this case. The AFC of the demodulator
- *  should make it still possible to receive the requested transponder 
- *  on both tuners...
- */
-static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive)
-{
-       struct list_head *entry;
-       int stepsize = this_fe->info->frequency_stepsize;
-       int this_fe_adap_num = this_fe->frontend.i2c->adapter->num;
-       int frequency;
-
-       if (!stepsize || recursive > 10) {
-               printk ("%s: too deep recursion, check frequency_stepsize "
-                       "in your frontend code!\n", __FUNCTION__);
-               return;
-       }
-
-       dprintk ("%s\n", __FUNCTION__);
-
-       if (!recursive) {
-               if (down_interruptible (&frontend_mutex))
-                       return;
-
-               this_fe->bending = 0;
-       }
-
-       list_for_each (entry, &frontend_list) {
-               struct dvb_frontend_data *fe;
-               int f;
-
-               fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
-               if (fe->frontend.i2c->adapter->num != this_fe_adap_num)
-                       continue;
-
-               f = fe->parameters.frequency;
-               f += fe->lnb_drift;
-               f += fe->bending;
-
-               frequency = this_fe->parameters.frequency;
-               frequency += this_fe->lnb_drift;
-               frequency += this_fe->bending;
-
-               if (this_fe != fe && (fe->state != FESTATE_IDLE) &&
-                    frequency > f - stepsize && frequency < f + stepsize)
-               {
-                       if (recursive % 2)
-                               this_fe->bending += stepsize;
-                       else
-                               this_fe->bending = -this_fe->bending;
-
-                       dvb_bend_frequency (this_fe, recursive + 1);
-                       goto done;
-               }
-       }
-done:
-       if (!recursive)
-               up (&frontend_mutex);
-}
-
-
-static void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe,
-                                 fe_status_t s)
-{
-       dprintk ("%s\n", __FUNCTION__);
-
-       if (((s ^ fe->status) & FE_HAS_LOCK) && (s & FE_HAS_LOCK))
-               dvb_delay (fe->info->notifier_delay);
-
-       fe->status = s;
-
-       if (!(s & FE_HAS_LOCK) && (fe->info->caps & FE_CAN_MUTE_TS))
-               return;
-
-       /**
-        *   now tell the Demux about the TS status changes...
-        */
-       if (fe->frontend.notifier_callback)
-               fe->frontend.notifier_callback(fe->status, fe->frontend.notifier_data);
-}
-
-
-static void dvb_frontend_add_event (struct dvb_frontend_data *fe, fe_status_t status)
+static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 {
        struct dvb_fe_events *events = &fe->events;
        struct dvb_frontend_event *e;
@@ -272,21 +113,19 @@ static void dvb_frontend_add_event (struct dvb_frontend_data *fe, fe_status_t st
                sizeof (struct dvb_frontend_parameters));
 
        if (status & FE_HAS_LOCK)
-               dvb_frontend_internal_ioctl (&fe->frontend,
-                                            FE_GET_FRONTEND,
-                                            &e->parameters);
+               if (fe->ops->get_frontend)
+                       fe->ops->get_frontend(fe, &e->parameters);
+
        events->eventw = wp;
 
        up (&events->sem);
 
        e->status = status;
-       dvb_call_frontend_notifiers (fe, status);
 
        wake_up_interruptible (&events->wait_queue);
 }
 
-
-static int dvb_frontend_get_event (struct dvb_frontend_data *fe,
+static int dvb_frontend_get_event(struct dvb_frontend *fe,
                            struct dvb_frontend_event *event, int flags)
 {
         struct dvb_fe_events *events = &fe->events;
@@ -329,15 +168,14 @@ static int dvb_frontend_get_event (struct dvb_frontend_data *fe,
         return 0;
 }
 
-static void dvb_frontend_init (struct dvb_frontend_data *fe)
+static void dvb_frontend_init(struct dvb_frontend *fe)
 {
-       struct dvb_frontend *frontend = &fe->frontend;
+       dprintk ("DVB: initialising frontend %i (%s)...\n",
+                fe->dvb->num,
+                fe->ops->info.name);
 
-       dprintk ("DVB: initialising frontend %i:%i (%s)...\n",
-                frontend->i2c->adapter->num, frontend->i2c->id,
-                fe->info->name);
-
-       dvb_frontend_internal_ioctl (frontend, FE_INIT, NULL);
+       if (fe->ops->init)
+               fe->ops->init(fe);
 }
 
 static void update_delay (int *quality, int *delay, int min_delay, int locked)
@@ -364,32 +202,33 @@ static void update_delay (int *quality, int *delay, int min_delay, int locked)
  * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
  * @returns Number of complete iterations that have been performed.
  */
-static int dvb_frontend_autotune(struct dvb_frontend_data *fe, int check_wrapped)
+static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
 {
        int autoinversion;
        int ready = 0;
        int original_inversion = fe->parameters.inversion;
        u32 original_frequency = fe->parameters.frequency;
 
-       // are we using autoinversion?
-       autoinversion = ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO));
+       /* are we using autoinversion? */
+       autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+                        (fe->parameters.inversion == INVERSION_AUTO));
 
-       // setup parameters correctly
+       /* setup parameters correctly */
        while(!ready) {
-               // calculate the lnb_drift
+               /* calculate the lnb_drift */
                fe->lnb_drift = fe->auto_step * fe->step_size;
 
-               // wrap the auto_step if we've exceeded the maximum drift
+               /* wrap the auto_step if we've exceeded the maximum drift */
                if (fe->lnb_drift > fe->max_drift) {
                        fe->auto_step = 0;
                        fe->auto_sub_step = 0;
                        fe->lnb_drift = 0;
                }
 
-               // perform inversion and +/- zigzag
+               /* perform inversion and +/- zigzag */
                switch(fe->auto_sub_step) {
                case 0:
-                       // try with the current inversion and current drift setting
+                       /* try with the current inversion and current drift setting */
                        ready = 1;
                        break;
 
@@ -418,42 +257,40 @@ static int dvb_frontend_autotune(struct dvb_frontend_data *fe, int check_wrapped
                    
                default:
                        fe->auto_step++;
-                       fe->auto_sub_step = -1; // it'll be incremented to 0 in a moment
+                       fe->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
                        break;
                }
            
                if (!ready) fe->auto_sub_step++;
        }
 
-       // if this attempt would hit where we started, indicate a complete iteration has occurred
-       if ((fe->auto_step == fe->started_auto_step) && (fe->auto_sub_step == 0) && check_wrapped) {
+       /* if this attempt would hit where we started, indicate a complete
+        * iteration has occurred */
+       if ((fe->auto_step == fe->started_auto_step) &&
+           (fe->auto_sub_step == 0) && check_wrapped) {
                return 1;
                }
 
-       // perform frequency bending if necessary
-       if ((dvb_override_frequency_bending != 1) && do_frequency_bending)
-               dvb_bend_frequency(fe, 0);
-
-       // instrumentation
-       dprintk("%s: drift:%i bending:%i inversion:%i auto_step:%i auto_sub_step:%i started_auto_step:%i\n", 
-               __FUNCTION__, fe->lnb_drift, fe->bending, fe->inversion, fe->auto_step, fe->auto_sub_step,
-               fe->started_auto_step);
+       dprintk("%s: drift:%i inversion:%i auto_step:%i "
+               "auto_sub_step:%i started_auto_step:%i\n",
+               __FUNCTION__, fe->lnb_drift, fe->inversion,
+               fe->auto_step, fe->auto_sub_step, fe->started_auto_step);
     
-       // set the frontend itself
-       fe->parameters.frequency += fe->lnb_drift + fe->bending;
-       if (autoinversion) fe->parameters.inversion = fe->inversion;
-       dvb_frontend_internal_ioctl (&fe->frontend, FE_SET_FRONTEND, &fe->parameters);
+       /* set the frontend itself */
+       fe->parameters.frequency += fe->lnb_drift;
+       if (autoinversion)
+               fe->parameters.inversion = fe->inversion;
+       if (fe->ops->set_frontend)
+               fe->ops->set_frontend(fe, &fe->parameters);
+
        fe->parameters.frequency = original_frequency;
        fe->parameters.inversion = original_inversion;
 
-       // normal return
        fe->auto_sub_step++;
        return 0;
 }
 
-
-
-static int dvb_frontend_is_exiting (struct dvb_frontend_data *fe)
+static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 {
        if (fe->exit)
                return 1;
@@ -465,7 +302,7 @@ static int dvb_frontend_is_exiting (struct dvb_frontend_data *fe)
        return 0;
 }
 
-static int dvb_frontend_should_wakeup (struct dvb_frontend_data *fe)
+static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
 {
        if (fe->wakeup) {
                fe->wakeup = 0;
@@ -474,14 +311,18 @@ static int dvb_frontend_should_wakeup (struct dvb_frontend_data *fe)
        return dvb_frontend_is_exiting(fe);
 }
 
-static void dvb_frontend_wakeup (struct dvb_frontend_data *fe) {
+static void dvb_frontend_wakeup(struct dvb_frontend *fe)
+{
        fe->wakeup = 1;
        wake_up_interruptible(&fe->wait_queue);
 }
 
+/*
+ * FIXME: use linux/kthread.h
+ */
 static int dvb_frontend_thread (void *data)
 {
-       struct dvb_frontend_data *fe = (struct dvb_frontend_data *) data;
+       struct dvb_frontend *fe = (struct dvb_frontend *) data;
        unsigned long timeout;
        char name [15];
        int quality = 0, delay = 3*HZ;
@@ -490,86 +331,101 @@ static int dvb_frontend_thread (void *data)
 
        dprintk ("%s\n", __FUNCTION__);
 
-       snprintf (name, sizeof(name), "kdvb-fe-%i:%i",
-                 fe->frontend.i2c->adapter->num, fe->frontend.i2c->id);
+       snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num);
 
-       dvb_kernel_thread_setup (name);
+        lock_kernel ();
+        daemonize (name);
+        sigfillset (&current->blocked);
+        unlock_kernel ();
 
-       dvb_call_frontend_notifiers (fe, 0);
+       fe->status = 0;
        dvb_frontend_init (fe);
        fe->wakeup = 0;
 
        while (1) {
                up (&fe->sem);      /* is locked when we enter the thread... */
 
-               timeout = wait_event_interruptible_timeout(fe->wait_queue,0 != dvb_frontend_should_wakeup (fe), delay);
-               if (-ERESTARTSYS == timeout || 0 != dvb_frontend_is_exiting (fe)) {
+               timeout = wait_event_interruptible_timeout(fe->wait_queue,
+                                                          dvb_frontend_should_wakeup(fe),
+                                                          delay);
+               if (0 != dvb_frontend_is_exiting (fe)) {
                        /* got signal or quitting */
                        break;
                }
 
+               if (current->flags & PF_FREEZE)
+                       refrigerator(PF_FREEZE);
+
                if (down_interruptible (&fe->sem))
                        break;
 
-               // if we've got no parameters, just keep idling
+               /* if we've got no parameters, just keep idling */
                if (fe->state & FESTATE_IDLE) {
                        delay = 3*HZ;
                        quality = 0;
                        continue;
                }
 
-               // get the frontend status
-               dvb_frontend_internal_ioctl (&fe->frontend, FE_READ_STATUS, &s);
-               if (s != fe->status)
+retune:
+               /* get the frontend status */
+               if (fe->state & FESTATE_RETUNE) {
+                       s = 0;
+               } else {
+                       if (fe->ops->read_status)
+                               fe->ops->read_status(fe, &s);
+                       if (s != fe->status) {
                        dvb_frontend_add_event (fe, s);
-
-               // if we're not tuned, and we have a lock, move to the TUNED state
+                               fe->status = s;
+                       }
+               }
+               /* if we're not tuned, and we have a lock, move to the TUNED state */
                if ((fe->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
                        update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
                        fe->state = FESTATE_TUNED;
 
-                       // if we're tuned, then we have determined the correct inversion
-                       if ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO)) {
+                       /* if we're tuned, then we have determined the correct inversion */
+                       if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+                           (fe->parameters.inversion == INVERSION_AUTO)) {
                                fe->parameters.inversion = fe->inversion;
                        }
                        continue;
                }
 
-               // if we are tuned already, check we're still locked
+               /* if we are tuned already, check we're still locked */
                if (fe->state & FESTATE_TUNED) {
                        update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
 
-                       // we're tuned, and the lock is still good...
-               if (s & FE_HAS_LOCK) {
+                       /* we're tuned, and the lock is still good... */
+                       if (s & FE_HAS_LOCK)
                                continue;
-               } else {
-                               // if we _WERE_ tuned, but now don't have a lock, need to zigzag
+                       else {
+                               /* if we _WERE_ tuned, but now don't have a lock,
+                                * need to zigzag */
                                fe->state = FESTATE_ZIGZAG_FAST;
                                fe->started_auto_step = fe->auto_step;
                                check_wrapped = 0;
-                               // fallthrough
                        }
                }
 
-               // don't actually do anything if we're in the LOSTLOCK state, the frontend is set to
-               // FE_CAN_RECOVER, and the max_drift is 0
+               /* don't actually do anything if we're in the LOSTLOCK state,
+                * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
                if ((fe->state & FESTATE_LOSTLOCK) && 
-                   (fe->info->caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) {
+                   (fe->ops->info.caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) {
                        update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
                                                continue;
                                }
            
-               // don't do anything if we're in the DISEQC state, since this might be someone
-               // with a motorized dish controlled by DISEQC. If its actually a re-tune, there will
-               // be a SET_FRONTEND soon enough.
+               /* don't do anything if we're in the DISEQC state, since this
+                * might be someone with a motorized dish controlled by DISEQC.
+                * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
                if (fe->state & FESTATE_DISEQC) {
                        update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
                        continue;
                                }
 
-               // if we're in the RETUNE state, set everything up for a brand new scan,
-               // keeping the current inversion setting, as the next tune is _very_ likely
-               // to require the same
+               /* if we're in the RETUNE state, set everything up for a brand
+                * new scan, keeping the current inversion setting, as the next
+                * tune is _very_ likely to require the same */
                if (fe->state & FESTATE_RETUNE) {
                        fe->lnb_drift = 0;
                        fe->auto_step = 0;
@@ -578,43 +434,47 @@ static int dvb_frontend_thread (void *data)
                        check_wrapped = 0;
                }
 
-               // fast zigzag.
+               /* fast zigzag. */
                if ((fe->state & FESTATE_SEARCHING_FAST) || (fe->state & FESTATE_RETUNE)) {
                        delay = fe->min_delay;
 
-                       // peform a tune
+                       /* peform a tune */
                        if (dvb_frontend_autotune(fe, check_wrapped)) {
-                               // OK, if we've run out of trials at the fast speed. Drop back to
-                               // slow for the _next_ attempt
+                               /* OK, if we've run out of trials at the fast speed.
+                                * Drop back to slow for the _next_ attempt */
                                fe->state = FESTATE_SEARCHING_SLOW;
                                fe->started_auto_step = fe->auto_step;
                                continue;
                        }
                        check_wrapped = 1;
 
-                       // if we've just retuned, enter the ZIGZAG_FAST state. This ensures
-                       // we cannot return from an FE_SET_FRONTEND ioctl before the first frontend
-                       // tune occurs
+                       /* if we've just retuned, enter the ZIGZAG_FAST state.
+                        * This ensures we cannot return from an
+                        * FE_SET_FRONTEND ioctl before the first frontend tune
+                        * occurs */
                        if (fe->state & FESTATE_RETUNE) {
                                fe->state = FESTATE_TUNING_FAST;
-                               wake_up_interruptible(&fe->wait_queue);
+                               goto retune;
                        }
                }
 
-               // slow zigzag
+               /* slow zigzag */
                if (fe->state & FESTATE_SEARCHING_SLOW) {
                        update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
                    
-                       // Note: don't bother checking for wrapping; we stay in this state 
-                       // until we get a lock
+                       /* Note: don't bother checking for wrapping; we stay in this
+                        * state until we get a lock */
                        dvb_frontend_autotune(fe, 0);
                }
-       };
-
-       if (dvb_shutdown_timeout)
-               dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL); 
+       }
 
-       up (&fe->sem);
+       if (dvb_shutdown_timeout) {
+               if (dvb_powerdown_on_sleep)
+                       if (fe->ops->set_voltage)
+                               fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF);
+               if (fe->ops->sleep)
+                       fe->ops->sleep(fe);
+       }
 
        fe->thread_pid = 0;
        mb();
@@ -623,8 +483,7 @@ static int dvb_frontend_thread (void *data)
        return 0;
 }
 
-
-static void dvb_frontend_stop (struct dvb_frontend_data *fe)
+static void dvb_frontend_stop(struct dvb_frontend *fe)
 {
        unsigned long ret;
 
@@ -662,8 +521,7 @@ static void dvb_frontend_stop (struct dvb_frontend_data *fe)
                                fe->thread_pid);
 }
 
-
-static int dvb_frontend_start (struct dvb_frontend_data *fe)
+static int dvb_frontend_start(struct dvb_frontend *fe)
 {
        int ret;
 
@@ -702,30 +560,120 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
                        unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend_data *fe = dvbdev->priv;
-       struct dvb_frontend_tune_settings fetunesettings;
-       int err = 0;
+       struct dvb_frontend *fe = dvbdev->priv;
+       int err = -EOPNOTSUPP;
 
        dprintk ("%s\n", __FUNCTION__);
 
-       if (!fe || !fe->frontend.ioctl || fe->exit)
+       if (!fe || fe->exit)
                return -ENODEV;
 
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
+           (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
+            cmd == FE_DISEQC_RECV_SLAVE_REPLY))
+               return -EPERM;
+
        if (down_interruptible (&fe->sem))
                return -ERESTARTSYS;
 
        switch (cmd) {
+       case FE_GET_INFO: {
+               struct dvb_frontend_info* info = (struct dvb_frontend_info*) parg;
+               memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info));
+
+               /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
+                * do it, it is done for it. */
+               info->caps |= FE_CAN_INVERSION_AUTO;
+               err = 0;
+               break;
+       }
+
+       case FE_READ_STATUS:
+               if (fe->ops->read_status)
+                       err = fe->ops->read_status(fe, (fe_status_t*) parg);
+               break;
+
+       case FE_READ_BER:
+               if (fe->ops->read_ber)
+                       err = fe->ops->read_ber(fe, (__u32*) parg);
+               break;
+
+       case FE_READ_SIGNAL_STRENGTH:
+               if (fe->ops->read_signal_strength)
+                       err = fe->ops->read_signal_strength(fe, (__u16*) parg);
+               break;
+
+       case FE_READ_SNR:
+               if (fe->ops->read_snr)
+                       err = fe->ops->read_snr(fe, (__u16*) parg);
+               break;
+
+       case FE_READ_UNCORRECTED_BLOCKS:
+               if (fe->ops->read_ucblocks)
+                       err = fe->ops->read_ucblocks(fe, (__u32*) parg);
+               break;
+
+
+       case FE_DISEQC_RESET_OVERLOAD:
+               if (fe->ops->diseqc_reset_overload) {
+                       err = fe->ops->diseqc_reset_overload(fe);
+                       fe->state = FESTATE_DISEQC;
+                       fe->status = 0;
+               }
+               break;
+
        case FE_DISEQC_SEND_MASTER_CMD:
+               if (fe->ops->diseqc_send_master_cmd) {
+                       err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+                       fe->state = FESTATE_DISEQC;
+                       fe->status = 0;
+               }
+               break;
+
        case FE_DISEQC_SEND_BURST:
+               if (fe->ops->diseqc_send_burst) {
+                       err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+                       fe->state = FESTATE_DISEQC;
+                       fe->status = 0;
+               }
+               break;
+
        case FE_SET_TONE:
-               if (fe->status)
-                       dvb_call_frontend_notifiers (fe, 0);
-               dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);
+               if (fe->ops->set_tone) {
+                       err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
+                       fe->state = FESTATE_DISEQC;
+                       fe->status = 0;
+               }
+               break;
+
+       case FE_SET_VOLTAGE:
+               if (fe->ops->set_voltage) {
+                       err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
                fe->state = FESTATE_DISEQC;
+                       fe->status = 0;
+               }
                break;
 
-       case FE_SET_FRONTEND:
-               fe->state = FESTATE_RETUNE;
+       case FE_DISHNETWORK_SEND_LEGACY_CMD:
+               if (fe->ops->dishnetwork_send_legacy_command) {
+                       err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
+                       fe->state = FESTATE_DISEQC;
+                       fe->status = 0;
+               }
+               break;
+
+       case FE_DISEQC_RECV_SLAVE_REPLY:
+               if (fe->ops->diseqc_recv_slave_reply)
+                       err = fe->ops->diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+               break;
+
+       case FE_ENABLE_HIGH_LNB_VOLTAGE:
+               if (fe->ops->enable_high_lnb_voltage);
+                       err = fe->ops->enable_high_lnb_voltage(fe, (int) parg);
+               break;
+
+       case FE_SET_FRONTEND: {
+               struct dvb_frontend_tune_settings fetunesettings;
            
                memcpy (&fe->parameters, parg,
                        sizeof (struct dvb_frontend_parameters));
@@ -734,75 +682,73 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
                memcpy(&fetunesettings.parameters, parg,
                       sizeof (struct dvb_frontend_parameters));
                    
-               // force auto frequency inversion if requested
+               /* force auto frequency inversion if requested */
                if (dvb_force_auto_inversion) {
                        fe->parameters.inversion = INVERSION_AUTO;
                        fetunesettings.parameters.inversion = INVERSION_AUTO;
                }
+               if (fe->ops->info.type == FE_OFDM) {
+                       /* without hierachical coding code_rate_LP is irrelevant,
+                        * so we tolerate the otherwise invalid FEC_NONE setting */
+                       if (fe->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
+                           fe->parameters.u.ofdm.code_rate_LP == FEC_NONE)
+                               fe->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
+               }
 
-               // get frontend-specific tuning settings
-               if (dvb_frontend_internal_ioctl(&fe->frontend, FE_GET_TUNE_SETTINGS, &fetunesettings) == 0) {
+               /* get frontend-specific tuning settings */
+               if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) {
                        fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
                        fe->max_drift = fetunesettings.max_drift;
                        fe->step_size = fetunesettings.step_size;
                } else {
-                       // default values
-                       switch(fe->info->type) {
+                       /* default values */
+                       switch(fe->ops->info.type) {
                        case FE_QPSK:
-                               fe->min_delay = HZ/20; // default mindelay of 50ms
+                               fe->min_delay = HZ/20;
                                fe->step_size = fe->parameters.u.qpsk.symbol_rate / 16000;
                                fe->max_drift = fe->parameters.u.qpsk.symbol_rate / 2000;
                break;
                            
                        case FE_QAM:
-                               fe->min_delay = HZ/20; // default mindelay of 50ms
-                               fe->step_size = 0;
-                               fe->max_drift = 0; // don't want any zigzagging under DVB-C frontends
+                               fe->min_delay = HZ/20;
+                               fe->step_size = 0; /* no zigzag */
+                               fe->max_drift = 0;
                                break;
                            
                        case FE_OFDM:
-                               fe->min_delay = HZ/20; // default mindelay of 50ms
-                               fe->step_size = fe->info->frequency_stepsize * 2;
-                               fe->max_drift = (fe->info->frequency_stepsize * 2) + 1;
+                               fe->min_delay = HZ/20;
+                               fe->step_size = fe->ops->info.frequency_stepsize * 2;
+                               fe->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
+                               break;
+                       case FE_ATSC:
+                               printk("dvb-core: FE_ATSC not handled yet.\n");
                                break;
                        }
                }
-               if (dvb_override_tune_delay > 0) {
+               if (dvb_override_tune_delay > 0)
                       fe->min_delay = (dvb_override_tune_delay * HZ) / 1000;
-               }
 
+               fe->state = FESTATE_RETUNE;
+               dvb_frontend_wakeup(fe);
                dvb_frontend_add_event (fe, 0);     
+               fe->status = 0;
+               err = 0;
                break;
+       }
 
        case FE_GET_EVENT:
                err = dvb_frontend_get_event (fe, parg, file->f_flags);
                break;
+
        case FE_GET_FRONTEND:
-               memcpy (parg, &fe->parameters,
-                       sizeof (struct dvb_frontend_parameters));
-               /*  fall-through... */
-       default:
-               err = dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);
+               if (fe->ops->get_frontend) {
+                       memcpy (parg, &fe->parameters, sizeof (struct dvb_frontend_parameters));
+                       err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
+               }
+               break;
        };
 
        up (&fe->sem);
-       if (err < 0)
-               return err;
-
-       // Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't do it, it is done for it.
-       if ((cmd == FE_GET_INFO) && (err == 0)) {
-               struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) parg;
-               tmp->caps |= FE_CAN_INVERSION_AUTO;
-       }
-
-       // if the frontend has just been set, wait until the first tune has finished.
-       // This ensures the app doesn't start reading data too quickly, perhaps from the
-       // previous lock, which is REALLY CONFUSING TO DEBUG!
-       if ((cmd == FE_SET_FRONTEND) && (err == 0)) {
-               dvb_frontend_wakeup(fe);
-               err = wait_event_interruptible(fe->wait_queue, fe->state & ~FESTATE_RETUNE);
-       }
-
        return err;
 }
 
@@ -810,7 +756,7 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
 static unsigned int dvb_frontend_poll (struct file *file, struct poll_table_struct *wait)
 {
        struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend_data *fe = dvbdev->priv;
+       struct dvb_frontend *fe = dvbdev->priv;
 
        dprintk ("%s\n", __FUNCTION__);
 
@@ -826,7 +772,7 @@ static unsigned int dvb_frontend_poll (struct file *file, struct poll_table_stru
 static int dvb_frontend_open (struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend_data *fe = dvbdev->priv;
+       struct dvb_frontend *fe = dvbdev->priv;
        int ret;
 
        dprintk ("%s\n", __FUNCTION__);
@@ -850,7 +796,7 @@ static int dvb_frontend_open (struct inode *inode, struct file *file)
 static int dvb_frontend_release (struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend_data *fe = dvbdev->priv;
+       struct dvb_frontend *fe = dvbdev->priv;
 
        dprintk ("%s\n", __FUNCTION__);
 
@@ -861,193 +807,6 @@ static int dvb_frontend_release (struct inode *inode, struct file *file)
 }
 
 
-
-int
-dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
-                         int (*before_ioctl) (struct dvb_frontend *frontend,
-                                              unsigned int cmd, void *arg),
-                         int (*after_ioctl)  (struct dvb_frontend *frontend,
-                                              unsigned int cmd, void *arg),
-                        void *before_after_data)
-{
-       struct dvb_frontend_ioctl_data *ioctl;
-        struct list_head *entry;
-
-       dprintk ("%s\n", __FUNCTION__);
-
-       if (down_interruptible (&frontend_mutex))
-               return -ERESTARTSYS;
-
-       ioctl = kmalloc (sizeof(struct dvb_frontend_ioctl_data), GFP_KERNEL);
-
-       if (!ioctl) {
-               up (&frontend_mutex);
-               return -ENOMEM;
-       }
-
-       ioctl->adapter = adapter;
-       ioctl->before_ioctl = before_ioctl;
-       ioctl->after_ioctl = after_ioctl;
-       ioctl->before_after_data = before_after_data;
-
-       list_add_tail (&ioctl->list_head, &frontend_ioctl_list);
-
-       list_for_each (entry, &frontend_list) {
-               struct dvb_frontend_data *fe;
-
-               fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
-               if (fe->frontend.i2c->adapter == adapter &&
-                   fe->frontend.before_ioctl == NULL &&
-                   fe->frontend.after_ioctl == NULL)
-               {
-                       fe->frontend.before_ioctl = before_ioctl;
-                       fe->frontend.after_ioctl = after_ioctl;
-                       fe->frontend.before_after_data = before_after_data;
-               }
-       }
-
-       up (&frontend_mutex);
-
-       return 0;
-}
-
-
-void
-dvb_remove_frontend_ioctls (struct dvb_adapter *adapter,
-                           int (*before_ioctl) (struct dvb_frontend *frontend,
-                                                 unsigned int cmd, void *arg),
-                            int (*after_ioctl)  (struct dvb_frontend *frontend,
-                                                 unsigned int cmd, void *arg))
-{
-       struct list_head *entry, *n;
-
-       dprintk ("%s\n", __FUNCTION__);
-
-       down (&frontend_mutex);
-
-       list_for_each (entry, &frontend_list) {
-               struct dvb_frontend_data *fe;
-
-               fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
-               if (fe->frontend.i2c->adapter == adapter &&
-                   fe->frontend.before_ioctl == before_ioctl &&
-                   fe->frontend.after_ioctl == after_ioctl)
-               {
-                       fe->frontend.before_ioctl = NULL;
-                       fe->frontend.after_ioctl = NULL;
-
-               }
-       }
-
-       list_for_each_safe (entry, n, &frontend_ioctl_list) {
-               struct dvb_frontend_ioctl_data *ioctl;
-
-               ioctl = list_entry (entry, struct dvb_frontend_ioctl_data, list_head);
-
-               if (ioctl->adapter == adapter &&
-                   ioctl->before_ioctl == before_ioctl &&
-                   ioctl->after_ioctl == after_ioctl)
-               {
-                       list_del (&ioctl->list_head);
-                       kfree (ioctl);
-                       
-                       break;
-               }
-       }
-
-       up (&frontend_mutex);
-}
-
-
-int
-dvb_add_frontend_notifier (struct dvb_adapter *adapter,
-                          void (*callback) (fe_status_t s, void *data),
-                          void *data)
-{
-       struct dvb_frontend_notifier_data *notifier;
-       struct list_head *entry;
-
-       dprintk ("%s\n", __FUNCTION__);
-
-       if (down_interruptible (&frontend_mutex))
-               return -ERESTARTSYS;
-
-       notifier = kmalloc (sizeof(struct dvb_frontend_notifier_data), GFP_KERNEL);
-
-       if (!notifier) {
-               up (&frontend_mutex);
-               return -ENOMEM;
-       }
-
-       notifier->adapter = adapter;
-       notifier->callback = callback;
-       notifier->data = data;
-
-       list_add_tail (&notifier->list_head, &frontend_notifier_list);
-
-       list_for_each (entry, &frontend_list) {
-               struct dvb_frontend_data *fe;
-
-               fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
-               if (fe->frontend.i2c->adapter == adapter &&
-                   fe->frontend.notifier_callback == NULL)
-               {
-                       fe->frontend.notifier_callback = callback;
-                       fe->frontend.notifier_data = data;
-               }
-       }
-
-       up (&frontend_mutex);
-
-       return 0;
-}
-
-
-void
-dvb_remove_frontend_notifier (struct dvb_adapter *adapter,
-                             void (*callback) (fe_status_t s, void *data))
-{
-       struct list_head *entry, *n;
-
-       dprintk ("%s\n", __FUNCTION__);
-
-       down (&frontend_mutex);
-
-       list_for_each (entry, &frontend_list) {
-               struct dvb_frontend_data *fe;
-
-               fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
-               if (fe->frontend.i2c->adapter == adapter &&
-                   fe->frontend.notifier_callback == callback)
-               {
-                       fe->frontend.notifier_callback = NULL;
-
-               }
-       }
-
-       list_for_each_safe (entry, n, &frontend_notifier_list) {
-               struct dvb_frontend_notifier_data *notifier;
-
-               notifier = list_entry (entry, struct dvb_frontend_notifier_data, list_head);
-
-               if (notifier->adapter == adapter &&
-                   notifier->callback == callback)
-               {
-                       list_del (&notifier->list_head);
-                       kfree (notifier);
-                       
-                       break;
-               }
-       }
-
-       up (&frontend_mutex);
-}
-
-
 static struct file_operations dvb_frontend_fops = {
        .owner          = THIS_MODULE,
        .ioctl          = dvb_generic_ioctl,
@@ -1056,17 +815,9 @@ static struct file_operations dvb_frontend_fops = {
        .release        = dvb_frontend_release
 };
 
-
-
-int
-dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
-                                    unsigned int cmd, void *arg),
-                      struct dvb_i2c_bus *i2c,
-                      void *data,
-                      struct dvb_frontend_info *info)
+int dvb_register_frontend(struct dvb_adapter* dvb,
+                         struct dvb_frontend* fe)
 {
-       struct list_head *entry;
-       struct dvb_frontend_data *fe;
        static const struct dvb_device dvbdev_template = {
                .users = ~0,
                .writers = 1,
@@ -1080,110 +831,39 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
        if (down_interruptible (&frontend_mutex))
                return -ERESTARTSYS;
 
-       if (!(fe = kmalloc (sizeof (struct dvb_frontend_data), GFP_KERNEL))) {
-               up (&frontend_mutex);
-               return -ENOMEM;
-       }
-
-       memset (fe, 0, sizeof (struct dvb_frontend_data));
-
        init_MUTEX (&fe->sem);
        init_waitqueue_head (&fe->wait_queue);
        init_waitqueue_head (&fe->events.wait_queue);
        init_MUTEX (&fe->events.sem);
        fe->events.eventw = fe->events.eventr = 0;
        fe->events.overflow = 0;
-
-       fe->frontend.ioctl = ioctl;
-       fe->frontend.i2c = i2c;
-       fe->frontend.data = data;
-       fe->info = info;
+       fe->dvb = dvb;
        fe->inversion = INVERSION_OFF;
 
-       list_for_each (entry, &frontend_ioctl_list) {
-               struct dvb_frontend_ioctl_data *ioctl;
-
-               ioctl = list_entry (entry,
-                                   struct dvb_frontend_ioctl_data,
-                                   list_head);
-
-               if (ioctl->adapter == i2c->adapter) {
-                       fe->frontend.before_ioctl = ioctl->before_ioctl;
-                       fe->frontend.after_ioctl = ioctl->after_ioctl;
-                       fe->frontend.before_after_data = ioctl->before_after_data;
-                       break;
-               }
-       }
-
-       list_for_each (entry, &frontend_notifier_list) {
-               struct dvb_frontend_notifier_data *notifier;
-
-               notifier = list_entry (entry,
-                                      struct dvb_frontend_notifier_data,
-                                      list_head);
+       printk ("DVB: registering frontend %i (%s)...\n",
+               fe->dvb->num,
+               fe->ops->info.name);
 
-               if (notifier->adapter == i2c->adapter) {
-                       fe->frontend.notifier_callback = notifier->callback;
-                       fe->frontend.notifier_data = notifier->data;
-                       break;
-               }
-       }
-
-       list_add_tail (&fe->list_head, &frontend_list);
-
-       printk ("DVB: registering frontend %i:%i (%s)...\n",
-               fe->frontend.i2c->adapter->num, fe->frontend.i2c->id,
-               fe->info->name);
-
-       dvb_register_device (i2c->adapter, &fe->dvbdev, &dvbdev_template,
+       dvb_register_device (fe->dvb, &fe->dvbdev, &dvbdev_template,
                             fe, DVB_DEVICE_FRONTEND);
 
-       if ((info->caps & FE_NEEDS_BENDING) || (dvb_override_frequency_bending == 2))
-               do_frequency_bending = 1;
-    
        up (&frontend_mutex);
-
        return 0;
 }
+EXPORT_SYMBOL(dvb_register_frontend);
 
-
-int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
-                                          unsigned int cmd, void *arg),
-                            struct dvb_i2c_bus *i2c)
+int dvb_unregister_frontend(struct dvb_frontend* fe)
 {
-        struct list_head *entry, *n;
-
        dprintk ("%s\n", __FUNCTION__);
 
        down (&frontend_mutex);
-
-       list_for_each_safe (entry, n, &frontend_list) {
-               struct dvb_frontend_data *fe;
-
-               fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
-               if (fe->frontend.ioctl == ioctl && fe->frontend.i2c == i2c) {
                        dvb_unregister_device (fe->dvbdev);
-                       list_del (entry);
-                       up (&frontend_mutex);
                        dvb_frontend_stop (fe);
-                       kfree (fe);
-                       return 0;
-               }
-       }
-
+       if (fe->ops->release)
+               fe->ops->release(fe);
+       else
+               printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
        up (&frontend_mutex);
-       return -EINVAL;
+       return 0;
 }
-
-MODULE_PARM(dvb_frontend_debug,"i");
-MODULE_PARM(dvb_shutdown_timeout,"i");
-MODULE_PARM(dvb_override_frequency_bending,"i");
-MODULE_PARM(dvb_force_auto_inversion,"i");
-MODULE_PARM(dvb_override_tune_delay,"i");
-
-MODULE_PARM_DESC(dvb_frontend_debug, "enable verbose debug messages");
-MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
-MODULE_PARM_DESC(dvb_override_frequency_bending, "0: normal (default), 1: never use frequency bending, 2: always use frequency bending");
-MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
-MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
+EXPORT_SYMBOL(dvb_unregister_frontend);
index 8d8e21f..038abac 100644 (file)
@@ -1,9 +1,12 @@
 /* 
  * dvb_frontend.h
  *
- * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
- *                    overhauled by Holger Waechtler for Convergence GmbH
+ * Copyright (C) 2001 convergence integrated media GmbH
+ * Copyright (C) 2004 convergence GmbH
  *
+ * Written by Ralph Metzler
+ * Overhauled by Holger Waechtler
+ * Kernel I2C stuff by Michael Hunold <hunold@convergence.de>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/errno.h>
+#include <linux/delay.h>
 
 #include <linux/dvb/frontend.h>
 
-#include "dvb_i2c.h"
 #include "dvbdev.h"
 
+/* FIXME: Move to i2c-id.h */
+#define I2C_DRIVERID_DVBFE_SP8870      I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_CX22700     I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_AT76C651    I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_CX24110     I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_CX22702     I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_DIB3000MB   I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_DST         I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_DUMMY       I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_L64781      I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_MT312       I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_MT352       I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_NXT6000     I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_SP887X      I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_STV0299     I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_TDA1004X    I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_TDA8083     I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_VES1820     I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_VES1X93     I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_TDA80XX     I2C_DRIVERID_EXP2
 
 
-
-/**
- *   when before_ioctl is registered and returns value 0, ioctl and after_ioctl
- *   are not executed.
- */
-
-struct dvb_frontend {
-       int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
-       int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
-       int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
-       void (*notifier_callback) (fe_status_t s, void *data);
-       struct dvb_i2c_bus *i2c;
-       void *before_after_data;   /*  can be used by hardware module... */
-       void *notifier_data;       /*  can be used by hardware module... */
-       void *data;                /*  can be used by hardware module... */
-};
-
 struct dvb_frontend_tune_settings {
         int min_delay_ms;
         int step_size;
@@ -63,65 +69,79 @@ struct dvb_frontend_tune_settings {
         struct dvb_frontend_parameters parameters;
 };
 
+struct dvb_frontend;
 
-/**
- *   private frontend command ioctl's.
- *   keep them in sync with the public ones defined in linux/dvb/frontend.h
- * 
- *   FE_SLEEP. Ioctl used to put frontend into a low power mode.
- *   FE_INIT. Ioctl used to initialise the frontend.
- *   FE_GET_TUNE_SETTINGS. Get the frontend-specific tuning loop settings for the supplied set of parameters.
- */
-#define FE_SLEEP              _IO('v', 80)
-#define FE_INIT               _IO('v', 81)
-#define FE_GET_TUNE_SETTINGS  _IOWR('v', 83, struct dvb_frontend_tune_settings)
-
-
-extern int
-dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
-                                    unsigned int cmd, void *arg),
-                      struct dvb_i2c_bus *i2c,
-                      void *data,
-                      struct dvb_frontend_info *info);
-
-extern int
-dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
-                                      unsigned int cmd, void *arg),
-                        struct dvb_i2c_bus *i2c);
-
-
-/**
- *  Add special ioctl code performed before and after the main ioctl
- *  to all frontend devices on the specified DVB adapter.
- *  This is necessairy because the 22kHz/13V-18V/DiSEqC stuff depends
- *  heavily on the hardware around the frontend, the same tuner can create 
- *  these signals on about a million different ways...
- *
- *  Return value: number of frontends where the ioctl's were applied.
- */
-extern int
-dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
-                        int (*before_ioctl) (struct dvb_frontend *frontend,
-                                             unsigned int cmd, void *arg),
-                        int (*after_ioctl)  (struct dvb_frontend *frontend,
-                                             unsigned int cmd, void *arg),
-                        void *before_after_data);
-
-
-extern void
-dvb_remove_frontend_ioctls (struct dvb_adapter *adapter,
-                           int (*before_ioctl) (struct dvb_frontend *frontend,
-                                                unsigned int cmd, void *arg),
-                           int (*after_ioctl)  (struct dvb_frontend *frontend,
-                                                unsigned int cmd, void *arg));
-
-extern int
-dvb_add_frontend_notifier (struct dvb_adapter *adapter,
-                          void (*callback) (fe_status_t s, void *data),
-                          void *data);
-extern void
-dvb_remove_frontend_notifier (struct dvb_adapter *adapter,
-                             void (*callback) (fe_status_t s, void *data));
+struct dvb_frontend_ops {
 
-#endif
+       struct dvb_frontend_info info;
+
+       void (*release)(struct dvb_frontend* fe);
+
+       int (*init)(struct dvb_frontend* fe);
+       int (*sleep)(struct dvb_frontend* fe);
+
+       int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+       int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+       int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
 
+       int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
+       int (*read_ber)(struct dvb_frontend* fe, u32* ber);
+       int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
+       int (*read_snr)(struct dvb_frontend* fe, u16* snr);
+       int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
+
+       int (*diseqc_reset_overload)(struct dvb_frontend* fe);
+       int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+       int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
+       int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+       int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+       int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+       int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg);
+       int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+};
+
+#define MAX_EVENT 8
+
+struct dvb_fe_events {
+       struct dvb_frontend_event events[MAX_EVENT];
+       int                       eventw;
+       int                       eventr;
+       int                       overflow;
+       wait_queue_head_t         wait_queue;
+       struct semaphore          sem;
+};
+
+struct dvb_frontend {
+       struct dvb_frontend_ops* ops;
+       struct dvb_adapter *dvb;
+       void* demodulator_priv;
+
+       struct dvb_device *dvbdev;
+       struct dvb_frontend_parameters parameters;
+       struct dvb_fe_events events;
+       struct semaphore sem;
+       struct list_head list_head;
+       wait_queue_head_t wait_queue;
+       pid_t thread_pid;
+       unsigned long release_jiffies;
+       int state;
+       int bending;
+       int lnb_drift;
+       int inversion;
+       int auto_step;
+       int auto_sub_step;
+       int started_auto_step;
+       int min_delay;
+       int max_drift;
+       int step_size;
+       int exit;
+       int wakeup;
+       fe_status_t status;
+};
+
+extern int dvb_register_frontend(struct dvb_adapter* dvb,
+                                struct dvb_frontend* fe);
+
+extern int dvb_unregister_frontend(struct dvb_frontend* fe);
+
+#endif
index fc4700f..333ada7 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/smp_lock.h>
 
 #define DVB_MAJOR 212
 
@@ -48,6 +49,7 @@ struct dvb_adapter {
        struct list_head device_list;
        const char *name;
        u8 proposed_mac [6];
+       void* priv;
 
        struct module *module;
 };
@@ -92,5 +94,15 @@ extern int dvb_generic_open (struct inode *inode, struct file *file);
 extern int dvb_generic_release (struct inode *inode, struct file *file);
 extern int dvb_generic_ioctl (struct inode *inode, struct file *file,
                              unsigned int cmd, unsigned long arg);
+
+/* we don't mess with video_usercopy() any more,
+we simply define out own dvb_usercopy(), which will hopefully become
+generic_usercopy()  someday... */
+
+extern int dvb_usercopy(struct inode *inode, struct file *file,
+                           unsigned int cmd, unsigned long arg,
+                           int (*func)(struct inode *inode, struct file *file,
+                           unsigned int cmd, void *arg));
+
 #endif /* #ifndef _DVBDEV_H_ */
 
index 812fff1..226a59b 100644 (file)
-comment "Supported Frontend Modules"
-       depends on DVB
-
-config DVB_TWINHAN_DST
-       tristate "TWINHAN DST based DVB-S frontend (QPSK)"
-       depends on DVB_CORE && DVB_BT8XX
-       help
-         Used in such cards as the VP-1020/1030, Twinhan DST,
-         VVmer TV@SAT. Say Y when you want to support frontends 
-         using this asic.
+menu "Customise DVB Frontends"
+       depends on DVB_CORE
 
-         This module requires the dvb-bt8xx driver and dvb bt878
-         module.
+comment "DVB-S (satellite) frontends"
+       depends on DVB_CORE
 
 config DVB_STV0299
-       tristate "STV0299 based DVB-S frontend (QPSK)"
+       tristate "ST STV0299 based"
        depends on DVB_CORE
        help
-         The stv0299 by ST is used in many DVB-S tuner modules, 
-         say Y when you want to support frontends based on this 
-         DVB-S demodulator.
-
-         Some examples are the Alps BSRU6, the Philips SU1278 and
-         the LG TDQB-S00x.
-
-         If you don't know what tuner module is soldered on your 
-         DVB adapter simply enable all supported frontends, the 
-         right one will get autodetected.
+         A DVB-S tuner module. Say Y when you want to support this frontend.
 
-config DVB_SP887X
-       tristate "Frontends with sp887x demodulators, e.g. Microtune DTF7072"
+config DVB_CX24110
+       tristate "Conexant CX24110 based"
        depends on DVB_CORE
        help
-         A DVB-T demodulator driver. Say Y when you want to support the sp887x.
+         A DVB-S tuner module. Say Y when you want to support this frontend.
  
-         If you don't know what tuner module is soldered on your
-         DVB adapter simply enable all supported frontends, the
-         right one will get autodetected.
+config DVB_TDA8083
+       tristate "Philips TDA8083 based"
+       depends on DVB_CORE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_TDA80XX
+       tristate "Philips TDA8044 or TDA8083 based"
+       depends on DVB_CORE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
 
-config DVB_SP887X_FIRMWARE_FILE
-        string "Full pathname of sp887x firmware file"
-        depends on DVB_SP887X
-        default "/usr/lib/hotplug/firmware/sc_main.mc"
-        help
-          This driver needs a copy of the Avermedia firmware. The version tested
-         is part of the Avermedia DVB-T 1.3.26.3 Application. This can be downloaded
-         from the Avermedia web site.
-         If the software is installed in Windows the file will be in the
-         /Program Files/AVerTV DVB-T/ directory and is called sc_main.mc.
-         Alternatively it can "extracted" from the install cab files but this will have
-         to be done in windows as I don't know of a linux version of extract.exe.
-         Copy this file to /usr/lib/hotplug/firmware/sc_main.mc.
-         With this version of the file the first 10 bytes are discarded and the next
-         0x4000 loaded. This may change in future versions.
+config DVB_MT312
+       tristate "Zarlink MT312 based"
+       depends on DVB_CORE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
 
-config DVB_ALPS_TDLB7
-       tristate "Alps TDLB7 (OFDM)"
+config DVB_VES1X93
+       tristate "VLSI VES1893 or VES1993 based"
        depends on DVB_CORE
        help
-         A DVB-T tuner module. Say Y when you want to support this frontend.
+         A DVB-S tuner module. Say Y when you want to support this frontend.
 
-         This tuner module needs some microcode located in a file called
-         "Sc_main.mc" in the windows driver. Please pass the module parameter
-         mcfile="/PATH/FILENAME" when loading alps_tdlb7.o.
+comment "DVB-T (terrestrial) frontends"
+       depends on DVB_CORE
 
-         If you don't know what tuner module is soldered on your
-         DVB adapter simply enable all supported frontends, the
-         right one will get autodetected.
+config DVB_SP8870
+       tristate "Spase sp8870 based"
+       depends on DVB_CORE
+       help
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
+         This driver needs external firmware. Please use the command
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware.
 
-config DVB_ALPS_TDMB7
-       tristate "Alps TDMB7 (OFDM)"
+config DVB_SP887X
+       tristate "Spase sp887x based"
        depends on DVB_CORE
        help
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
-         If you don't know what tuner module is soldered on your
-         DVB adapter simply enable all supported frontends, the
-         right one will get autodetected.
+         This driver needs external firmware. Please use the command
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware.
 
-config DVB_ATMEL_AT76C651
-       tristate "Atmel AT76C651 (QAM)"
+config DVB_CX22700
+       tristate "Conexant CX22700 based"
        depends on DVB_CORE
        help
-         The AT76C651 Demodulator is used in some DVB-C SetTopBoxes. Say Y
-         when you see this demodulator chip near your tuner module.
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
-         If you don't know what tuner module is soldered on your
-         DVB adapter simply enable all supported frontends, the
-         right one will get autodetected.
+config DVB_CX22702
+       tristate "Conexant cx22702 demodulator (OFDM)"
+       depends on DVB_CORE
+       help
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
-config DVB_CX24110
-       tristate "Frontends with Connexant CX24110 demodulator (QPSK)"
+config DVB_L64781
+       tristate "LSI L64781"
        depends on DVB_CORE
        help
-         The CX24110 Demodulator is used in some DVB-S frontends. 
-         Say Y if you want support for this chip in your kernel.
-
-         If you don't know what tuner module is soldered on your 
-         DVB adapter simply enable all supported frontends, the 
-         right one will get autodetected.
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
-config DVB_GRUNDIG_29504_491
-       tristate "Grundig 29504-491 (QPSK)"
+config DVB_TDA1004X
+       tristate "Philips TDA10045H/TDA10046H based"
        depends on DVB_CORE
        help
-         A DVB-S tuner module. Say Y when you want to support this frontend.
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
-         If you don't know what tuner module is soldered on your 
-         DVB adapter simply enable all supported frontends, the 
-         right one will get autodetected.
+         This driver needs external firmware. Please use the commands
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+         download/extract them, and then copy them to /usr/lib/hotplug/firmware.
 
-config DVB_GRUNDIG_29504_401
-       tristate "Grundig 29504-401 (OFDM)"
+config DVB_NXT6000
+       tristate "NxtWave Communications NXT6000 based"
        depends on DVB_CORE
        help
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
-         If you don't know what tuner module is soldered on your 
-         DVB adapter simply enable all supported frontends, the 
-         right one will get autodetected.
-
-config DVB_MT312
-       tristate "Zarlink MT312 Satellite Channel Decoder (QPSK)"
+config DVB_MT352
+       tristate "Zarlink MT352 based"
        depends on DVB_CORE
        help
-         A DVB-S tuner module. Say Y when you want to support this frontend.
-
-         If you don't know what tuner module is soldered on your 
-         DVB adapter simply enable all supported frontends, the 
-         right one will get autodetected.
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
-config DVB_VES1820
-       tristate "Frontends with external VES1820 demodulator (QAM)"
+config DVB_DIB3000MB
+       tristate "DiBcom 3000-MB"
        depends on DVB_CORE
        help
-         The VES1820 Demodulator is used on many DVB-C PCI cards and in some
-         DVB-C SetTopBoxes. Say Y when you see this demodulator chip near your
-         tuner module.
+         A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+         to support this frontend.
 
-         If you don't know what tuner module is soldered on your 
-         DVB adapter simply enable all supported frontends, the 
-         right one will get autodetected.
-
-config DVB_VES1X93
-       tristate "Frontends with VES1893 or VES1993 demodulator (QPSK)"
+config DVB_DIB3000MC
+       tristate "DiBcom 3000-MC/P"
        depends on DVB_CORE
        help
-         A DVB-S tuner module. Say Y when you want to support this frontend.
+         A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+         to support this frontend.
 
-         If you don't know what tuner module is soldered on your 
-         DVB adapter simply enable all supported frontends, the 
-         right one will get autodetected.
+comment "DVB-C (cable) frontends"
+       depends on DVB_CORE
 
-config DVB_TDA1004X
-       tristate "Frontends with external TDA10045H or TDA10046H demodulators (OFDM)"
+config DVB_ATMEL_AT76C651
+       tristate "Atmel AT76C651 based"
        depends on DVB_CORE
-       help
-         A DVB-T tuner module. Say Y when you want to support this frontend.
+        help
+         A DVB-C tuner module. Say Y when you want to support this frontend.
 
-         If you don't know what tuner module is soldered on your
-         DVB adapter simply enable all supported frontends, the
-         right one will get autodetected.
+config DVB_VES1820
+       tristate "VLSI VES1820 based"
+       depends on DVB_CORE
+       help
+         A DVB-C tuner module. Say Y when you want to support this frontend.
 
-config DVB_TDA1004X_FIRMWARE_FILE
-        string "Full pathname of tda1004x.bin firmware file"
-        depends on DVB_TDA1004X
-        default "/usr/lib/hotplug/firmware/tda1004x.bin"
-        help
-          The TDA1004X requires additional firmware in order to function.
-          The firmware file can obtained as follows:
-            wget http://www.technotrend.de/new/215/TTweb_215a_budget_20_05_2003.zip
-            unzip -j TTweb_215a_budget_20_05_2003.zip Software/Oem/PCI/App/ttlcdacc.dll
-            mv ttlcdacc.dll /usr/lib/hotplug/firmware/tda1004x.bin
-         Note: even if you're using a USB device, you MUST get the file from the
-         TechnoTrend PCI drivers.
+config DVB_TDA10021
+       tristate "Philips TDA10021 based"
+       depends on DVB_CORE
+       help
+         A DVB-C tuner module. Say Y when you want to support this frontend.
 
-config DVB_NXT6000
-       tristate "Frontends with NxtWave Communications NXT6000 demodulator (OFDM)"
+config DVB_STV0297
+       tristate "ST STV0297 based"
        depends on DVB_CORE
        help
-         A DVB-T tuner module. Say Y when you want to support this frontend.
+         A DVB-C tuner module. Say Y when you want to support this frontend.
 
-         If you don't know what tuner module is soldered on your
-         DVB adapter simply enable all supported frontends, the
-         right one will get autodetected.
+endmenu
index e536b0d..f84a498 100644 (file)
@@ -4,17 +4,23 @@
 
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
 
-obj-$(CONFIG_DVB_TWINHAN_DST) += dst.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
-obj-$(CONFIG_DVB_ALPS_TDLB7) += alps_tdlb7.o
-obj-$(CONFIG_DVB_ALPS_TDMB7) += alps_tdmb7.o
+obj-$(CONFIG_DVB_SP8870) += sp8870.o
+obj-$(CONFIG_DVB_CX22700) += cx22700.o
 obj-$(CONFIG_DVB_ATMEL_AT76C651) += at76c651.o
 obj-$(CONFIG_DVB_CX24110) += cx24110.o
-obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o
-obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o
+obj-$(CONFIG_DVB_TDA8083) += tda8083.o
+obj-$(CONFIG_DVB_L64781) += l64781.o
+obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o dib3000-common.o
+obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dib3000-common.o
 obj-$(CONFIG_DVB_MT312) += mt312.o
 obj-$(CONFIG_DVB_VES1820) += ves1820.o
 obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
 obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
 obj-$(CONFIG_DVB_SP887X) += sp887x.o
 obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
+obj-$(CONFIG_DVB_MT352) += mt352.o
+obj-$(CONFIG_DVB_CX22702) += cx22702.o
+obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o
+obj-$(CONFIG_DVB_TDA10021) += tda10021.o
+obj-$(CONFIG_DVB_STV0297) += stv0297.o
index 01d438a..4b6c539 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * at76c651.c
  * 
- * Atmel DVB-C Frontend Driver (at76c651/dat7021)
+ * Atmel DVB-C Frontend Driver (at76c651/tua6010xs)
  *
  * Copyright (C) 2001 fnbrd <fnbrd@gmx.de>
- *             & 2002 Andreas Oberritter <obi@linuxtv.org>
+ *             & 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
  * 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
  */
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/bitops.h>
+#include "dvb_frontend.h"
+#include "at76c651.h"
 
-#if defined(__powerpc__)
-#include <asm/bitops.h>
-#endif
 
-#include "dvb_frontend.h"
-#include "dvb_i2c.h"
-#include "dvb_functions.h"
+struct at76c651_state {
 
-static int debug = 0;
-static u8 at76c651_qam;
-static u8 at76c651_revision;
+       struct i2c_adapter* i2c;
 
-#define dprintk        if (debug) printk
+       struct dvb_frontend_ops ops;
 
-/*
- * DAT7021
- * -------
- * Input Frequency Range (RF): 48.25 MHz to 863.25 MHz
- * Band Width: 8 MHz
- * Level Input (Range for Digital Signals): -61 dBm to -41 dBm
- * Output Frequency (IF): 36 MHz
- *
- * (see http://www.atmel.com/atmel/acrobat/doc1320.pdf)
- */
+       const struct at76c651_config* config;
+
+       struct dvb_frontend frontend;
+
+       /* revision of the chip */
+       u8 revision;
 
-static struct dvb_frontend_info at76c651_info = {
-
-       .name = "Atmel AT76C651(B) with DAT7021",
-       .type = FE_QAM,
-       .frequency_min = 48250000,
-       .frequency_max = 863250000,
-       .frequency_stepsize = 62500,
-       /*.frequency_tolerance = */     /* FIXME: 12% of SR */
-       .symbol_rate_min = 0,           /* FIXME */
-       .symbol_rate_max = 9360000,     /* FIXME */
-       .symbol_rate_tolerance = 4000,
-       .notifier_delay = 0,
-       .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_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 |
-           FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER
+       /* last QAM value set */
+       u8 qam;
 };
 
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "at76c651: " args); \
+       } while (0)
+
+
 #if ! defined(__powerpc__)
 static __inline__ int __ilog2(unsigned long x)
 {
@@ -89,229 +76,150 @@ static __inline__ int __ilog2(unsigned long x)
 }
 #endif
 
-static int at76c651_writereg(struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int at76c651_writereg(struct at76c651_state* state, u8 reg, u8 data)
 {
-
        int ret;
        u8 buf[] = { reg, data };
-       struct i2c_msg msg = { .addr = 0x1a >> 1, .flags = 0, .buf = buf, .len = 2 };
+       struct i2c_msg msg =
+               { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
 
-       ret = i2c->xfer(i2c, &msg, 1);
+       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);
 
-       dvb_delay(10);
+       msleep(10);
 
        return (ret != 1) ? -EREMOTEIO : 0;
-
 }
 
-static u8 at76c651_readreg(struct dvb_i2c_bus *i2c, u8 reg)
+static u8 at76c651_readreg(struct at76c651_state* state, u8 reg)
 {
-
        int ret;
-       u8 b0[] = { reg };
-       u8 b1[] = { 0 };
-       struct i2c_msg msg[] = { {.addr =  0x1a >> 1, .flags =  0, .buf =  b0, .len = 1},
-                         {.addr =  0x1a >> 1, .flags =  I2C_M_RD, .buf =  b1, .len = 1} };
+       u8 val;
+       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 = &val, .len = 1 }
+       };
 
-       ret = i2c->xfer(i2c, msg, 2);
+       ret = i2c_transfer(state->i2c, msg, 2);
 
        if (ret != 2)
                dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
 
-       return b1[0];
-
+       return val;
 }
 
-static int at76c651_reset(struct dvb_i2c_bus *i2c)
+static int at76c651_reset(struct at76c651_state* state)
 {
-
-       return at76c651_writereg(i2c, 0x07, 0x01);
-
+       return at76c651_writereg(state, 0x07, 0x01);
 }
 
-static int at76c651_disable_interrupts(struct dvb_i2c_bus *i2c)
+static void at76c651_disable_interrupts(struct at76c651_state* state)
 {
-
-       return at76c651_writereg(i2c, 0x0b, 0x00);
-
+       at76c651_writereg(state, 0x0b, 0x00);
 }
 
-static int at76c651_set_auto_config(struct dvb_i2c_bus *i2c)
+static int at76c651_set_auto_config(struct at76c651_state *state)
 {
-
        /*
         * Autoconfig
         */
 
-       at76c651_writereg(i2c, 0x06, 0x01);
+       at76c651_writereg(state, 0x06, 0x01);
 
        /*
         * Performance optimizations, should be done after autoconfig
         */
 
-       at76c651_writereg(i2c, 0x10, 0x06);
-       at76c651_writereg(i2c, 0x11, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0x12 : 0x10);
-       at76c651_writereg(i2c, 0x15, 0x28);
-       at76c651_writereg(i2c, 0x20, 0x09);
-       at76c651_writereg(i2c, 0x24, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0xC0 : 0x90);
-       at76c651_writereg(i2c, 0x30, 0x90);
-       if (at76c651_qam == 5)
-               at76c651_writereg(i2c, 0x35, 0x2A);
+       at76c651_writereg(state, 0x10, 0x06);
+       at76c651_writereg(state, 0x11, ((state->qam == 5) || (state->qam == 7)) ? 0x12 : 0x10);
+       at76c651_writereg(state, 0x15, 0x28);
+       at76c651_writereg(state, 0x20, 0x09);
+       at76c651_writereg(state, 0x24, ((state->qam == 5) || (state->qam == 7)) ? 0xC0 : 0x90);
+       at76c651_writereg(state, 0x30, 0x90);
+       if (state->qam == 5)
+               at76c651_writereg(state, 0x35, 0x2A);
 
        /*
         * Initialize A/D-converter
         */
 
-       if (at76c651_revision == 0x11) {
-               at76c651_writereg(i2c, 0x2E, 0x38);
-               at76c651_writereg(i2c, 0x2F, 0x13);
+       if (state->revision == 0x11) {
+               at76c651_writereg(state, 0x2E, 0x38);
+               at76c651_writereg(state, 0x2F, 0x13);
 }
 
-       at76c651_disable_interrupts(i2c);
+       at76c651_disable_interrupts(state);
 
        /*
         * Restart operation
         */
 
-       at76c651_reset(i2c);
-
-       return 0;
-
-}
-
-static int at76c651_set_bbfreq(struct dvb_i2c_bus *i2c)
-{
-
-       at76c651_writereg(i2c, 0x04, 0x3f);
-       at76c651_writereg(i2c, 0x05, 0xee);
-
-       return 0;
-
-}
-
-static int at76c651_switch_tuner_i2c(struct dvb_i2c_bus *i2c, u8 enable)
-{
-
-       if (enable)
-               return at76c651_writereg(i2c, 0x0c, 0xc2 | 0x01);
-       else
-               return at76c651_writereg(i2c, 0x0c, 0xc2);
-
-}
-
-static int dat7021_write(struct dvb_i2c_bus *i2c, u32 tw)
-{
-
-       int ret;
-       struct i2c_msg msg =
-           { .addr = 0xc2 >> 1, .flags = 0, .buf = (u8 *) & tw, .len = sizeof (tw) };
-
-#ifdef __LITTLE_ENDIAN
-       tw = __cpu_to_be32(tw);
-#endif
-
-       at76c651_switch_tuner_i2c(i2c, 1);
-
-       ret = i2c->xfer(i2c, &msg, 1);
-
-       at76c651_switch_tuner_i2c(i2c, 0);
-
-       if (ret != 4)
-               return -EFAULT;
-
-       at76c651_reset(i2c);
+       at76c651_reset(state);
 
        return 0;
-
 }
 
-static int dat7021_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq)
+static void at76c651_set_bbfreq(struct at76c651_state* state)
 {
-
-       u32 dw;
-
-       freq /= 1000;
-
-       if ((freq < 48250) || (freq > 863250))
-               return -EINVAL;
-
-       /*
-        * formula: dw=0x17e28e06+(freq-346000UL)/8000UL*0x800000
-        *      or: dw=0x4E28E06+(freq-42000) / 125 * 0x20000
-        */
-
-       dw = (freq - 42000) * 4096;
-       dw = dw / 125;
-       dw = dw * 32;
-
-       if (freq > 394000)
-               dw += 0x4E28E85;
-       else
-               dw += 0x4E28E06;
-
-       return dat7021_write(i2c, dw);
-
+       at76c651_writereg(state, 0x04, 0x3f);
+       at76c651_writereg(state, 0x05, 0xee);
 }
 
-static int at76c651_set_symbolrate(struct dvb_i2c_bus *i2c, u32 symbolrate)
+static int at76c651_set_symbol_rate(struct at76c651_state* state, u32 symbol_rate)
 {
-
        u8 exponent;
        u32 mantissa;
 
-       if (symbolrate > 9360000)
+       if (symbol_rate > 9360000)
                return -EINVAL;
 
        /*
         * FREF = 57800 kHz
-        * exponent = 10 + floor ( log2 ( symbolrate / FREF ) )
-        * mantissa = ( symbolrate / FREF) * ( 1 << ( 30 - exponent ) )
+        * exponent = 10 + floor (log2(symbol_rate / FREF))
+        * mantissa = (symbol_rate / FREF) * (1 << (30 - exponent))
         */
 
-       exponent = __ilog2((symbolrate << 4) / 903125);
-       mantissa = ((symbolrate / 3125) * (1 << (24 - exponent))) / 289;
+       exponent = __ilog2((symbol_rate << 4) / 903125);
+       mantissa = ((symbol_rate / 3125) * (1 << (24 - exponent))) / 289;
 
-       at76c651_writereg(i2c, 0x00, mantissa >> 13);
-       at76c651_writereg(i2c, 0x01, mantissa >> 5);
-       at76c651_writereg(i2c, 0x02, (mantissa << 3) | exponent);
+       at76c651_writereg(state, 0x00, mantissa >> 13);
+       at76c651_writereg(state, 0x01, mantissa >> 5);
+       at76c651_writereg(state, 0x02, (mantissa << 3) | exponent);
 
        return 0;
-
 }
 
-static int at76c651_set_qam(struct dvb_i2c_bus *i2c, fe_modulation_t qam)
+static int at76c651_set_qam(struct at76c651_state *state, fe_modulation_t qam)
 {
-
        switch (qam) {
        case QPSK:
-               at76c651_qam = 0x02;
+               state->qam = 0x02;
                break;
        case QAM_16:
-               at76c651_qam = 0x04;
+               state->qam = 0x04;
                break;
        case QAM_32:
-               at76c651_qam = 0x05;
+               state->qam = 0x05;
                break;
        case QAM_64:
-               at76c651_qam = 0x06;
+               state->qam = 0x06;
                break;
        case QAM_128:
-               at76c651_qam = 0x07;
+               state->qam = 0x07;
                break;
        case QAM_256:
-               at76c651_qam = 0x08;
+               state->qam = 0x08;
                break;
 #if 0
        case QAM_512:
-               at76c651_qam = 0x09;
+               state->qam = 0x09;
                break;
        case QAM_1024:
-               at76c651_qam = 0x0A;
+               state->qam = 0x0A;
                break;
 #endif
        default:
@@ -319,15 +227,12 @@ static int at76c651_set_qam(struct dvb_i2c_bus *i2c, fe_modulation_t qam)
 
        }
 
-       return at76c651_writereg(i2c, 0x03, at76c651_qam);
-
+       return at76c651_writereg(state, 0x03, state->qam);
 }
 
-static int at76c651_set_inversion(struct dvb_i2c_bus *i2c,
-                      fe_spectral_inversion_t inversion)
+static int at76c651_set_inversion(struct at76c651_state* state, fe_spectral_inversion_t inversion)
 {
-
-       u8 feciqinv = at76c651_readreg(i2c, 0x60);
+       u8 feciqinv = at76c651_readreg(state, 0x60);
 
        switch (inversion) {
        case INVERSION_OFF:
@@ -347,56 +252,63 @@ static int at76c651_set_inversion(struct dvb_i2c_bus *i2c,
                return -EINVAL;
        }
 
-       return at76c651_writereg(i2c, 0x60, feciqinv);
-
+       return at76c651_writereg(state, 0x60, feciqinv);
 }
 
-static int at76c651_set_parameters(struct dvb_i2c_bus *i2c,
-                       struct dvb_frontend_parameters *p)
-{
 
-       dat7021_set_tv_freq(i2c, p->frequency);
-       at76c651_set_symbolrate(i2c, p->u.qam.symbol_rate);
-       at76c651_set_inversion(i2c, p->inversion);
-       at76c651_set_auto_config(i2c);
-        at76c651_reset(i2c);
 
-       return 0;
 
-}
 
-static int at76c651_set_defaults(struct dvb_i2c_bus *i2c)
+
+
+
+
+static int at76c651_set_parameters(struct dvb_frontend* fe,
+                       struct dvb_frontend_parameters *p)
 {
+       int ret;
+       struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
 
-       at76c651_set_symbolrate(i2c, 6900000);
-       at76c651_set_qam(i2c, QAM_64);
-       at76c651_set_bbfreq(i2c);
-       at76c651_set_auto_config(i2c);
+       at76c651_writereg(state, 0x0c, 0xc3);
+       state->config->pll_set(fe, p);
+       at76c651_writereg(state, 0x0c, 0xc2);
 
-       return 0;
+       if ((ret = at76c651_set_symbol_rate(state, p->u.qam.symbol_rate)))
+               return ret;
 
+       if ((ret = at76c651_set_inversion(state, p->inversion)))
+               return ret;
+
+       return at76c651_set_auto_config(state);
 }
 
-static int at76c651_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int at76c651_set_defaults(struct dvb_frontend* fe)
 {
+       struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
 
-       switch (cmd) {
+       at76c651_set_symbol_rate(state, 6900000);
+       at76c651_set_qam(state, QAM_64);
+       at76c651_set_bbfreq(state);
+       at76c651_set_auto_config(state);
 
-       case FE_GET_INFO:
-               memcpy(arg, &at76c651_info, sizeof (struct dvb_frontend_info));
-               break;
+       if (state->config->pll_init) {
+               at76c651_writereg(state, 0x0c, 0xc3);
+               state->config->pll_init(fe);
+               at76c651_writereg(state, 0x0c, 0xc2);
+}
 
-       case FE_READ_STATUS:
-               {
+       return 0;
+}
 
-                       fe_status_t *status = (fe_status_t *) arg;
+static int at76c651_read_status(struct dvb_frontend* fe, fe_status_t* status)
+               {
+       struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
                        u8 sync;
 
                        /*
                         * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0) 
                         */
-                       sync = at76c651_readreg(fe->i2c, 0x80);
-
+       sync = at76c651_readreg(state, 0x80);
                        *status = 0;
 
                        if (sync & (0x04 | 0x10))       /* AGC1 || TIM */
@@ -414,122 +326,138 @@ static int at76c651_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
                        if ((sync & 0xF0) == 0xF0)      /* TIM && EQU && CAR && FEC */
                                *status |= FE_HAS_LOCK;
 
-                       break;
-
+       return 0;
                }
 
-       case FE_READ_BER:
+static int at76c651_read_ber(struct dvb_frontend* fe, u32* ber)
                {
-                       u32 *ber = (u32 *) arg;
+       struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
 
-                       *ber = (at76c651_readreg(fe->i2c, 0x81) & 0x0F) << 16;
-                       *ber |= at76c651_readreg(fe->i2c, 0x82) << 8;
-                       *ber |= at76c651_readreg(fe->i2c, 0x83);
+       *ber = (at76c651_readreg(state, 0x81) & 0x0F) << 16;
+       *ber |= at76c651_readreg(state, 0x82) << 8;
+       *ber |= at76c651_readreg(state, 0x83);
                        *ber *= 10;
 
-                       break;
+       return 0;
                }
 
-       case FE_READ_SIGNAL_STRENGTH:
+static int at76c651_read_signal_strength(struct dvb_frontend* fe, u16* strength)
                {
-                       u8 gain = ~at76c651_readreg(fe->i2c, 0x91);
-
-                       *(u16 *) arg = (gain << 8) | gain;
-                       break;
-               }
+       struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
 
-       case FE_READ_SNR:
-               *(u16 *) arg =
-                   0xFFFF -
-                   ((at76c651_readreg(fe->i2c, 0x8F) << 8) |
-                    at76c651_readreg(fe->i2c, 0x90));
-               break;
+       u8 gain = ~at76c651_readreg(state, 0x91);
+       *strength = (gain << 8) | gain;
 
-       case FE_READ_UNCORRECTED_BLOCKS:
-               *(u32 *) arg = at76c651_readreg(fe->i2c, 0x82);
-               break;
+       return 0;
+}
 
-       case FE_SET_FRONTEND:
-               return at76c651_set_parameters(fe->i2c, arg);
+static int at76c651_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
 
-       case FE_GET_FRONTEND:
-               break;
+       *snr = 0xFFFF -
+           ((at76c651_readreg(state, 0x8F) << 8) |
+            at76c651_readreg(state, 0x90));
 
-       case FE_SLEEP:
-               break;
 
-       case FE_INIT:
-               return at76c651_set_defaults(fe->i2c);
+       return 0;
+}
 
-       case FE_GET_TUNE_SETTINGS:
+static int at76c651_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        {
-               struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
-               fesettings->min_delay_ms = 50;
-               fesettings->step_size = 0;
-               fesettings->max_drift = 0;
-               return 0;
-       }           
+       struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
 
-       default:
-               return -ENOIOCTLCMD;
-       }
+       *ucblocks = at76c651_readreg(state, 0x82);
 
        return 0;
-
 }
 
-static int at76c651_attach(struct dvb_i2c_bus *i2c, void **data)
+static int at76c651_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *fesettings)
 {
-       if ( (at76c651_readreg(i2c, 0x0E) != 0x65) ||
-            ( ( (at76c651_revision = at76c651_readreg(i2c, 0x0F)) & 0xFE) != 0x10) )
-{
-               dprintk("no AT76C651(B) found\n");
-               return -ENODEV;
+        fesettings->min_delay_ms = 50;
+        fesettings->step_size = 0;
+        fesettings->max_drift = 0;
+       return 0;
        }
 
-       if (at76c651_revision == 0x10)
-       {
-               dprintk("AT76C651A found\n");
-               strcpy(at76c651_info.name,"Atmel AT76C651A with DAT7021");
-               }
-       else
-       {
-               strcpy(at76c651_info.name,"Atmel AT76C651B with DAT7021");
-               dprintk("AT76C651B found\n");
+static void at76c651_release(struct dvb_frontend* fe)
+{
+       struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
+               kfree(state);
        }
 
-       at76c651_set_defaults(i2c);
-
-       return dvb_register_frontend(at76c651_ioctl, i2c, NULL, &at76c651_info);
+static struct dvb_frontend_ops at76c651_ops;
 
-}
-
-static void at76c651_detach(struct dvb_i2c_bus *i2c, void *data)
+struct dvb_frontend* at76c651_attach(const struct at76c651_config* config,
+                                    struct i2c_adapter* i2c)
 {
+       struct at76c651_state* state = NULL;
 
-       dvb_unregister_frontend(at76c651_ioctl, i2c);
+       /* allocate memory for the internal state */
+       state = (struct at76c651_state*) kmalloc(sizeof(struct at76c651_state), GFP_KERNEL);
+       if (state == NULL) goto error;
 
-}
+       /* setup the state */
+       state->config = config;
+       state->qam = 0;
 
-static int __init at76c651_init(void)
-{
+       /* check if the demod is there */
+       if (at76c651_readreg(state, 0x0e) != 0x65) goto error;
 
-       return dvb_register_i2c_device(THIS_MODULE, at76c651_attach,
-                                      at76c651_detach);
+       /* finalise state setup */
+       state->i2c = i2c;
+       state->revision = at76c651_readreg(state, 0x0f) & 0xfe;
+       memcpy(&state->ops, &at76c651_ops, sizeof(struct dvb_frontend_ops));
 
-}
-
-static void __exit at76c651_exit(void)
-{
-
-       dvb_unregister_i2c_device(at76c651_attach);
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
 
+error:
+       if (state) kfree(state);
+       return NULL;
 }
 
-module_init(at76c651_init);
-module_exit(at76c651_exit);
+static struct dvb_frontend_ops at76c651_ops = {
+
+       .info = {
+               .name = "Atmel AT76C651B DVB-C",
+               .type = FE_QAM,
+               .frequency_min = 48250000,
+               .frequency_max = 863250000,
+               .frequency_stepsize = 62500,
+               /*.frequency_tolerance = */     /* FIXME: 12% of SR */
+               .symbol_rate_min = 0,           /* FIXME */
+               .symbol_rate_max = 9360000,     /* FIXME */
+               .symbol_rate_tolerance = 4000,
+               .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_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 |
+                   FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER
+       },
+
+       .release = at76c651_release,
+
+       .init = at76c651_set_defaults,
+
+       .set_frontend = at76c651_set_parameters,
+       .get_tune_settings = at76c651_get_tune_settings,
+
+       .read_status = at76c651_read_status,
+       .read_ber = at76c651_read_ber,
+       .read_signal_strength = at76c651_read_signal_strength,
+       .read_snr = at76c651_read_snr,
+       .read_ucblocks = at76c651_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
-MODULE_DESCRIPTION("at76c651/dat7021 dvb-c frontend driver");
+MODULE_DESCRIPTION("Atmel AT76C651 DVB-C Demodulator Driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
 MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
+
+EXPORT_SYMBOL(at76c651_attach);
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
index ee4d9a8..f8d5ec9 100644 (file)
@@ -1,6 +1,5 @@
 /*
     cx24110 - Single Chip Satellite Channel Receiver driver module
-               used on the the Pinnacle PCTV Sat cards
 
     Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on
     work
 
 */
 
-/* currently drives the Conexant cx24110 and cx24106 QPSK decoder chips,
-   connected via i2c to a Conexant Fusion 878 (this uses the standard
-   linux bttv driver). The tuner chip is supposed to be the Conexant
-   cx24108 digital satellite tuner, driven through the tuner interface
-   of the cx24110. SEC is also supplied by the cx24110.
-
-   Oct-2002: Migrate to API V3 (formerly known as NEWSTRUCT)
-*/
-
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
-
-static int debug = 0;
-#define dprintk        if (debug) printk
-
-
-static struct dvb_frontend_info cx24110_info = {
-       .name = "Conexant CX24110 with CX24108 tuner, aka HM1221/HM1811",
-       .type = FE_QPSK,
-       .frequency_min = 950000,
-       .frequency_max = 2150000,
-       .frequency_stepsize = 1011,  /* kHz for QPSK frontends, can be reduced
-                                       to 253kHz on the cx24108 tuner */
-       .frequency_tolerance = 29500,
-       .symbol_rate_min = 1000000,
-       .symbol_rate_max = 45000000,
-/*      .symbol_rate_tolerance = ???,*/
-       .notifier_delay = 50,                /* 1/20 s */
-       .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_RECOVER
+#include "cx24110.h"
+
+
+struct cx24110_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       const struct cx24110_config* config;
+
+       struct dvb_frontend frontend;
+
+       u32 lastber;
+       u32 lastbler;
+       u32 lastesn0;
 };
-/* fixme: are these values correct? especially ..._tolerance and caps */
 
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "cx24110: " args); \
+       } while (0)
 
 static struct {u8 reg; u8 data;} cx24110_regdata[]=
                       /* Comments beginning with @ denote this value should
@@ -127,16 +116,15 @@ static struct {u8 reg; u8 data;} cx24110_regdata[]=
        };
 
 
-static int cx24110_writereg (struct dvb_i2c_bus *i2c, int reg, int data)
+static int cx24110_writereg (struct cx24110_state* state, int reg, int data)
 {
         u8 buf [] = { reg, data };
-       struct i2c_msg msg = { .addr = 0x55, .flags = 0, .buf = buf, .len = 2 };
-/* fixme (medium): HW allows any i2c address. 0x55 is the default, but the
-   cx24110 might show up at any address */
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
        int err;
 
-        if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
-               dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+        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;
        }
 
@@ -144,161 +132,46 @@ static int cx24110_writereg (struct dvb_i2c_bus *i2c, int reg, int data)
 }
 
 
-static u8 cx24110_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static int cx24110_readreg (struct cx24110_state* state, u8 reg)
 {
        int ret;
        u8 b0 [] = { reg };
        u8 b1 [] = { 0 };
-       struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 },
-                          { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-/* fixme (medium): address might be different from 0x55 */
-       ret = i2c->xfer (i2c, msg, 2);
-
-       if (ret != 2)
-               dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
-
-       return b1[0];
-}
-
-
-static int cx24108_write (struct dvb_i2c_bus *i2c, u32 data)
-{
-/* tuner data is 21 bits long, must be left-aligned in data */
-/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
-/* FIXME (low): add error handling, avoid infinite loops if HW fails... */
-
-dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data);
-
-        cx24110_writereg(i2c,0x6d,0x30); /* auto mode at 62kHz */
-        cx24110_writereg(i2c,0x70,0x15); /* auto mode 21 bits */
-        /* if the auto tuner writer is still busy, clear it out */
-        while (cx24110_readreg(i2c,0x6d)&0x80)
-               cx24110_writereg(i2c,0x72,0);
-        /* write the topmost 8 bits */
-        cx24110_writereg(i2c,0x72,(data>>24)&0xff);
-        /* wait for the send to be completed */
-        while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
-               ;
-        /* send another 8 bytes */
-        cx24110_writereg(i2c,0x72,(data>>16)&0xff);
-        while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
-               ;
-        /* and the topmost 5 bits of this byte */
-        cx24110_writereg(i2c,0x72,(data>>8)&0xff);
-        while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
-               ;
-        /* now strobe the enable line once */
-        cx24110_writereg(i2c,0x6d,0x32);
-        cx24110_writereg(i2c,0x6d,0x30);
-
-        return 0;
-}
-
-
-static int cx24108_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
-{
-/* fixme (low): error handling */
-        int i, a, n, pump;
-        u32 band, pll;
-
-
-        static const u32 osci[]={ 950000,1019000,1075000,1178000,
-                                1296000,1432000,1576000,1718000,
-                                1856000,2036000,2150000};
-        static const u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,
-                                     0x00101000,0x00102000,0x00104000,
-                                     0x00108000,0x00110000,0x00120000,
-                                     0x00140000};
-
-#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
-        dprintk("cx24110 debug: cx24108_set_tv_freq, freq=%d\n",freq);
-
-        if (freq<950000)
-               freq=950000; /* kHz */
-        if (freq>2150000)
-               freq=2150000; /* satellite IF is 950..2150MHz */
-        /* decide which VCO to use for the input frequency */
-        for (i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++)
-               ;
-        dprintk("cx24110 debug: select vco #%d (f=%d)\n",i,freq);
-        band=bandsel[i];
-        /* the gain values must be set by SetSymbolrate */
-        /* compute the pll divider needed, from Conexant data sheet,
-           resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
-           depending on the divider bit. It is set to /4 on the 2 lowest
-           bands  */
-        n=((i<=2?2:1)*freq*10L)/(XTAL/100);
-        a=n%32; n/=32;
-       if (a==0)
-               n--;
-        pump=(freq<(osci[i-1]+osci[i])/2);
-        pll=0xf8000000|
-            ((pump?1:2)<<(14+11))|
-            ((n&0x1ff)<<(5+11))|
-            ((a&0x1f)<<11);
-        /* everything is shifted left 11 bits to left-align the bits in the
-           32bit word. Output to the tuner goes MSB-aligned, after all */
-        dprintk("cx24110 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
-        cx24108_write(i2c,band);
-        /* set vga and vca to their widest-band settings, as a precaution.
-           SetSymbolrate might not be called to set this up */
-        cx24108_write(i2c,0x500c0000);
-        cx24108_write(i2c,0x83f1f800);
-        cx24108_write(i2c,pll);
-        cx24110_writereg(i2c,0x56,0x7f);
-
-       dvb_delay(10); /* wait a moment for the tuner pll to lock */
-
-       /* tuner pll lock can be monitored on GPIO pin 4 of cx24110 */
-        while (!(cx24110_readreg(i2c,0x66)&0x20)&&i<1000)
-               i++;
-        dprintk("cx24110 debug: GPIO IN=%2.2x(loop=%d)\n",
-                cx24110_readreg(i2c,0x66),i);
-        return 0;
-
-}
-
-
-static int cx24110_init (struct dvb_i2c_bus *i2c)
-{
-/* fixme (low): error handling */
-        int i;
+       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: init chip\n", __FUNCTION__);
+       ret = i2c_transfer(state->i2c, msg, 2);
 
-        for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {
-               cx24110_writereg(i2c,cx24110_regdata[i].reg,cx24110_regdata[i].data);
-        };
+       if (ret != 2) return ret;
 
-       return 0;
+       return b1[0];
 }
 
-
-static int cx24110_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion_t inversion)
+static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inversion_t inversion)
 {
 /* fixme (low): error handling */
 
        switch (inversion) {
        case INVERSION_OFF:
-                cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x1);
+                cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
                 /* AcqSpectrInvDis on. No idea why someone should want this */
-                cx24110_writereg(i2c,0x5,cx24110_readreg(i2c,0x5)&0xf7);
+                cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7);
                 /* Initial value 0 at start of acq */
-                cx24110_writereg(i2c,0x22,cx24110_readreg(i2c,0x22)&0xef);
+                cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef);
                 /* current value 0 */
                 /* The cx24110 manual tells us this reg is read-only.
                    But what the heck... set it ayways */
                 break;
        case INVERSION_ON:
-                cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x1);
+                cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
                 /* AcqSpectrInvDis on. No idea why someone should want this */
-                cx24110_writereg(i2c,0x5,cx24110_readreg(i2c,0x5)|0x08);
+                cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08);
                 /* Initial value 1 at start of acq */
-                cx24110_writereg(i2c,0x22,cx24110_readreg(i2c,0x22)|0x10);
+                cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10);
                 /* current value 1 */
                 break;
        case INVERSION_AUTO:
-                cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)&0xfe);
+                cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe);
                 /* AcqSpectrInvDis off. Leave initial & current states as is */
                 break;
        default:
@@ -309,7 +182,7 @@ static int cx24110_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion
 }
 
 
-static int cx24110_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
+static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec)
 {
 /* fixme (low): error handling */
 
@@ -325,27 +198,27 @@ static int cx24110_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
                 fec=FEC_AUTO;
 
         if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */
-               cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)&0xdf);
+               cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf);
                /* clear AcqVitDis bit */
-               cx24110_writereg(i2c,0x18,0xae);
+               cx24110_writereg(state,0x18,0xae);
                /* allow all DVB standard code rates */
-               cx24110_writereg(i2c,0x05,(cx24110_readreg(i2c,0x05)&0xf0)|0x3);
+               cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3);
                /* set nominal Viterbi rate 3/4 */
-               cx24110_writereg(i2c,0x22,(cx24110_readreg(i2c,0x22)&0xf0)|0x3);
+               cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3);
                /* set current Viterbi rate 3/4 */
-               cx24110_writereg(i2c,0x1a,0x05); cx24110_writereg(i2c,0x1b,0x06);
+               cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06);
                /* set the puncture registers for code rate 3/4 */
                return 0;
         } else {
-               cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x20);
+               cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20);
                /* set AcqVitDis bit */
                if(rate[fec]>0) {
-                       cx24110_writereg(i2c,0x05,(cx24110_readreg(i2c,0x05)&0xf0)|rate[fec]);
+                       cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]);
                        /* set nominal Viterbi rate */
-                       cx24110_writereg(i2c,0x22,(cx24110_readreg(i2c,0x22)&0xf0)|rate[fec]);
+                       cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]);
                        /* set current Viterbi rate */
-                       cx24110_writereg(i2c,0x1a,g1[fec]);
-                       cx24110_writereg(i2c,0x1b,g2[fec]);
+                       cx24110_writereg(state,0x1a,g1[fec]);
+                       cx24110_writereg(state,0x1b,g2[fec]);
                        /* not sure if this is the right way: I always used AutoAcq mode */
            } else
                   return -EOPNOTSUPP;
@@ -355,11 +228,11 @@ static int cx24110_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
 }
 
 
-static fe_code_rate_t cx24110_get_fec (struct dvb_i2c_bus *i2c)
+static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state)
 {
        int i;
 
-       i=cx24110_readreg(i2c,0x22)&0x0f;
+       i=cx24110_readreg(state,0x22)&0x0f;
        if(!(i&0x08)) {
                return FEC_1_2 + i - 1;
        } else {
@@ -372,16 +245,13 @@ static fe_code_rate_t cx24110_get_fec (struct dvb_i2c_bus *i2c)
 }
 
 
-static int cx24110_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
+static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
 {
 /* fixme (low): add error handling */
         u32 ratio;
         u32 tmp, fclk, BDRI;
 
         static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
-        static const u32 vca[]={0x80f03800,0x81f0f800,0x83f1f800};
-        static const u32 vga[]={0x5f8fc000,0x580f0000,0x500c0000};
-        static const u8  filtune[]={0xa2,0xcc,0x66};
         int i;
 
 dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
@@ -395,22 +265,22 @@ dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
         /* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
            and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
            R06[3:0] PLLphaseDetGain */
-        tmp=cx24110_readreg(i2c,0x07)&0xfc;
+        tmp=cx24110_readreg(state,0x07)&0xfc;
         if(srate<90999000UL/4) { /* sample rate 45MHz*/
-               cx24110_writereg(i2c,0x07,tmp);
-               cx24110_writereg(i2c,0x06,0x78);
+               cx24110_writereg(state,0x07,tmp);
+               cx24110_writereg(state,0x06,0x78);
                fclk=90999000UL/2;
         } else if(srate<60666000UL/2) { /* sample rate 60MHz */
-               cx24110_writereg(i2c,0x07,tmp|0x1);
-               cx24110_writereg(i2c,0x06,0xa5);
+               cx24110_writereg(state,0x07,tmp|0x1);
+               cx24110_writereg(state,0x06,0xa5);
                fclk=60666000UL;
         } else if(srate<80888000UL/2) { /* sample rate 80MHz */
-               cx24110_writereg(i2c,0x07,tmp|0x2);
-               cx24110_writereg(i2c,0x06,0x87);
+               cx24110_writereg(state,0x07,tmp|0x2);
+               cx24110_writereg(state,0x06,0x87);
                fclk=80888000UL;
         } else { /* sample rate 90MHz */
-               cx24110_writereg(i2c,0x07,tmp|0x3);
-               cx24110_writereg(i2c,0x06,0x78);
+               cx24110_writereg(state,0x07,tmp|0x3);
+               cx24110_writereg(state,0x06,0x78);
                fclk=90999000UL;
         };
         dprintk("cx24110 debug: fclk %d Hz\n",fclk);
@@ -439,62 +309,123 @@ dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
         dprintk("fclk = %d\n", fclk);
         dprintk("ratio= %08x\n", ratio);
 
-        cx24110_writereg(i2c, 0x1, (ratio>>16)&0xff);
-        cx24110_writereg(i2c, 0x2, (ratio>>8)&0xff);
-        cx24110_writereg(i2c, 0x3, (ratio)&0xff);
+        cx24110_writereg(state, 0x1, (ratio>>16)&0xff);
+        cx24110_writereg(state, 0x2, (ratio>>8)&0xff);
+        cx24110_writereg(state, 0x3, (ratio)&0xff);
+
+        return 0;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+int cx24110_pll_write (struct dvb_frontend* fe, u32 data)
+{
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+
+/* tuner data is 21 bits long, must be left-aligned in data */
+/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
+/* FIXME (low): add error handling, avoid infinite loops if HW fails... */
+
+       dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data);
+
+        cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */
+        cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */
+
+        /* if the auto tuner writer is still busy, clear it out */
+        while (cx24110_readreg(state,0x6d)&0x80)
+               cx24110_writereg(state,0x72,0);
+
+        /* write the topmost 8 bits */
+        cx24110_writereg(state,0x72,(data>>24)&0xff);
+
+        /* wait for the send to be completed */
+        while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+               ;
+
+        /* send another 8 bytes */
+        cx24110_writereg(state,0x72,(data>>16)&0xff);
+        while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+               ;
 
-        /* please see the cx24108 data sheet, this controls tuner gain
-           and bandwidth settings depending on the symbol rate */
-        cx24108_write(i2c,vga[i]);
-        cx24108_write(i2c,vca[i]); /* gain is set on tuner chip */
-        cx24110_writereg(i2c,0x56,filtune[i]); /* bw is contolled by filtune voltage */
+        /* and the topmost 5 bits of this byte */
+        cx24110_writereg(state,0x72,(data>>8)&0xff);
+        while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+               ;
+
+        /* now strobe the enable line once */
+        cx24110_writereg(state,0x6d,0x32);
+        cx24110_writereg(state,0x6d,0x30);
 
         return 0;
+}
+
+
+
+static int cx24110_initfe(struct dvb_frontend* fe)
+{
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+/* fixme (low): error handling */
+        int i;
+
+       dprintk("%s: init chip\n", __FUNCTION__);
 
+        for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {
+               cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
+        };
+
+       if (state->config->pll_init) state->config->pll_init(fe);
+
+       return 0;
 }
 
 
-static int cx24110_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
+static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+
        switch (voltage) {
        case SEC_VOLTAGE_13:
-               return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0xc0);
+               return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0);
        case SEC_VOLTAGE_18:
-               return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0x40);
+               return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40);
        default:
                return -EINVAL;
        };
 }
 
-static void sendDiSEqCMessage(struct dvb_i2c_bus *i2c, struct dvb_diseqc_master_cmd *pCmd)
+static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
+                                   struct dvb_diseqc_master_cmd *cmd)
 {
        int i, rv;
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
 
-       for (i = 0; i < pCmd->msg_len; i++)
-               cx24110_writereg(i2c, 0x79 + i, pCmd->msg[i]);
+       for (i = 0; i < cmd->msg_len; i++)
+               cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
 
-       rv = cx24110_readreg(i2c, 0x76);
+       rv = cx24110_readreg(state, 0x76);
 
-       cx24110_writereg(i2c, 0x76, ((rv & 0x90) | 0x40) | ((pCmd->msg_len-3) & 3));
-       for (i=500; i-- > 0 && !(cx24110_readreg(i2c,0x76)&0x40);)
+       cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
+       for (i=500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40);)
                ; /* wait for LNB ready */
-}
 
+       return 0;
+}
 
-static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-       struct dvb_i2c_bus *i2c = fe->i2c;
-       static int lastber=0, lastbyer=0,lastbler=0, lastesn0=0, sum_bler=0;
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
 
-        switch (cmd) {
-        case FE_GET_INFO:
-               memcpy (arg, &cx24110_info, sizeof(struct dvb_frontend_info));
-               break;
-
-        case FE_READ_STATUS:
-       {
-               fe_status_t *status = arg;
-               int sync = cx24110_readreg (i2c, 0x55);
+       int sync = cx24110_readreg (state, 0x55);
 
                *status = 0;
 
@@ -504,7 +435,7 @@ static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
                if (sync & 0x08)
                        *status |= FE_HAS_CARRIER;
 
-               sync = cx24110_readreg (i2c, 0x08);
+       sync = cx24110_readreg (state, 0x08);
 
                if (sync & 0x40)
                        *status |= FE_HAS_VITERBI;
@@ -515,87 +446,97 @@ static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
                if ((sync & 0x60) == 0x60)
                        *status |= FE_HAS_LOCK;
 
-               if(cx24110_readreg(i2c,0x10)&0x40) {
-                       /* the RS error counter has finished one counting window */
-                       cx24110_writereg(i2c,0x10,0x60); /* select the byer reg */
-                       lastbyer=cx24110_readreg(i2c,0x12)|
-                               (cx24110_readreg(i2c,0x13)<<8)|
-                               (cx24110_readreg(i2c,0x14)<<16);
-                       cx24110_writereg(i2c,0x10,0x70); /* select the bler reg */
-                       lastbler=cx24110_readreg(i2c,0x12)|
-                               (cx24110_readreg(i2c,0x13)<<8)|
-                               (cx24110_readreg(i2c,0x14)<<16);
-                       cx24110_writereg(i2c,0x10,0x20); /* start new count window */
-                       sum_bler += lastbler;
-               }
-               if(cx24110_readreg(i2c,0x24)&0x10) {
-                       /* the Viterbi error counter has finished one counting window */
-                       cx24110_writereg(i2c,0x24,0x04); /* select the ber reg */
-                       lastber=cx24110_readreg(i2c,0x25)|
-                               (cx24110_readreg(i2c,0x26)<<8);
-                       cx24110_writereg(i2c,0x24,0x04); /* start new count window */
-                       cx24110_writereg(i2c,0x24,0x14);
-               }
-               if(cx24110_readreg(i2c,0x6a)&0x80) {
-                       /* the Es/N0 error counter has finished one counting window */
-                       lastesn0=cx24110_readreg(i2c,0x69)|
-                               (cx24110_readreg(i2c,0x68)<<8);
-                       cx24110_writereg(i2c,0x6a,0x84); /* start new count window */
-               }
-               break;
+       return 0;
        }
 
-        case FE_READ_BER:
+static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber)
        {
-               u32 *ber = (u32 *) arg;
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
 
-               *ber = lastber;
 /* fixme (maybe): value range is 16 bit. Scale? */
-               break;
+       if(cx24110_readreg(state,0x24)&0x10) {
+               /* the Viterbi error counter has finished one counting window */
+               cx24110_writereg(state,0x24,0x04); /* select the ber reg */
+               state->lastber=cx24110_readreg(state,0x25)|
+                       (cx24110_readreg(state,0x26)<<8);
+               cx24110_writereg(state,0x24,0x04); /* start new count window */
+               cx24110_writereg(state,0x24,0x14);
        }
+       *ber = state->lastber;
 
-        case FE_READ_SIGNAL_STRENGTH:
+       return 0;
+       }
+
+static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
        {
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+
 /* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */
-               u8 signal = cx24110_readreg (i2c, 0x27)+128;
-               *((u16*) arg) = (signal << 8) | signal;
-               break;
+       u8 signal = cx24110_readreg (state, 0x27)+128;
+       *signal_strength = (signal << 8) | signal;
+
+       return 0;
        }
 
-        case FE_READ_SNR:
+static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr)
        {
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+
 /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
-               *(u16*) arg = lastesn0;
-               break;
+       if(cx24110_readreg(state,0x6a)&0x80) {
+               /* the Es/N0 error counter has finished one counting window */
+               state->lastesn0=cx24110_readreg(state,0x69)|
+                       (cx24110_readreg(state,0x68)<<8);
+               cx24110_writereg(state,0x6a,0x84); /* start new count window */
        }
+       *snr = state->lastesn0;
 
-       case FE_READ_UNCORRECTED_BLOCKS:
+       return 0;
+       }
+
+static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        {
-               *(u16*) arg = sum_bler&0xffff;
-               sum_bler=0;
-               break;
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+       u32 lastbyer;
+
+       if(cx24110_readreg(state,0x10)&0x40) {
+               /* the RS error counter has finished one counting window */
+               cx24110_writereg(state,0x10,0x60); /* select the byer reg */
+               lastbyer=cx24110_readreg(state,0x12)|
+                       (cx24110_readreg(state,0x13)<<8)|
+                       (cx24110_readreg(state,0x14)<<16);
+               cx24110_writereg(state,0x10,0x70); /* select the bler reg */
+               state->lastbler=cx24110_readreg(state,0x12)|
+                       (cx24110_readreg(state,0x13)<<8)|
+                       (cx24110_readreg(state,0x14)<<16);
+               cx24110_writereg(state,0x10,0x20); /* start new count window */
        }
+       *ucblocks = state->lastbler;
 
-        case FE_SET_FRONTEND:
+       return 0;
+}
+
+static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
         {
-               struct dvb_frontend_parameters *p = arg;
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
 
-               cx24108_set_tv_freq (i2c, p->frequency);
-               cx24110_set_inversion (i2c, p->inversion);
-               cx24110_set_fec (i2c, p->u.qpsk.fec_inner);
-               cx24110_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
-               cx24110_writereg(i2c,0x04,0x05); /* start aquisition */
-                break;
+       state->config->pll_set(fe, p);
+       cx24110_set_inversion (state, p->inversion);
+       cx24110_set_fec (state, p->u.qpsk.fec_inner);
+       cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
+       cx24110_writereg(state,0x04,0x05); /* start aquisition */
+
+       return 0;
         }
 
-       case FE_GET_FRONTEND:
+static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
        {
-               struct dvb_frontend_parameters *p = arg;
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
                s32 afc; unsigned sclk;
 
 /* cannot read back tuner settings (freq). Need to have some private storage */
 
-               sclk = cx24110_readreg (i2c, 0x07) & 0x03;
+       sclk = cx24110_readreg (state, 0x07) & 0x03;
 /* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz.
  * Need 64 bit arithmetic. Is thiss possible in the kernel? */
                if (sclk==0) sclk=90999000L/2L;
@@ -603,76 +544,104 @@ static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
                else if (sclk==2) sclk=80888000L;
                else sclk=90999000L;
                sclk>>=8;
-               afc = sclk*(cx24110_readreg (i2c, 0x44)&0x1f)+
-                     ((sclk*cx24110_readreg (i2c, 0x45))>>8)+
-                     ((sclk*cx24110_readreg (i2c, 0x46))>>16);
+       afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+
+             ((sclk*cx24110_readreg (state, 0x45))>>8)+
+             ((sclk*cx24110_readreg (state, 0x46))>>16);
 
                p->frequency += afc;
-               p->inversion = (cx24110_readreg (i2c, 0x22) & 0x10) ?
+       p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
                                        INVERSION_ON : INVERSION_OFF;
-               p->u.qpsk.fec_inner = cx24110_get_fec (i2c);
-               break;
-       }
-
-        case FE_SLEEP:
-/* cannot do this from the FE end. How to communicate this to the place where it can be done? */
-               break;
-        case FE_INIT:
-               return cx24110_init (i2c);
-
-       case FE_SET_TONE:
-               return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&~0x10)|((((fe_sec_tone_mode_t) arg)==SEC_TONE_ON)?0x10:0));
-       case FE_SET_VOLTAGE:
-               return cx24110_set_voltage (i2c, (fe_sec_voltage_t) arg);
-
-       case FE_DISEQC_SEND_MASTER_CMD:
-               sendDiSEqCMessage(i2c, (struct dvb_diseqc_master_cmd*) arg);
-               return 0;
-
-       default:
-               return -EOPNOTSUPP;
-        };
+       p->u.qpsk.fec_inner = cx24110_get_fec (state);
 
         return 0;
 }
 
-
-static int cx24110_attach (struct dvb_i2c_bus *i2c, void **data)
+static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-       u8 sig;
-
-       sig=cx24110_readreg (i2c, 0x00);
-       if ( sig != 0x5a && sig != 0x69 )
-               return -ENODEV;
+       struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
 
-       return dvb_register_frontend (cx24110_ioctl, i2c, NULL, &cx24110_info);
+       return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0));
 }
 
-
-static void cx24110_detach (struct dvb_i2c_bus *i2c, void *data)
+static void cx24110_release(struct dvb_frontend* fe)
 {
-       dvb_unregister_frontend (cx24110_ioctl, i2c);
+       struct cx24110_state* state = (struct cx24110_state*) fe->demodulator_priv;
+               kfree(state);
 }
 
+static struct dvb_frontend_ops cx24110_ops;
 
-static int __init init_cx24110 (void)
+struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+                                   struct i2c_adapter* i2c)
 {
-       return dvb_register_i2c_device (THIS_MODULE, cx24110_attach, cx24110_detach);
-}
-
+       struct cx24110_state* state = NULL;
+       int ret;
 
-static void __exit exit_cx24110 (void)
-{
-       dvb_unregister_i2c_device (cx24110_attach);
+       /* allocate memory for the internal state */
+       state = (struct cx24110_state*) kmalloc(sizeof(struct cx24110_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
+       state->lastber = 0;
+       state->lastbler = 0;
+       state->lastesn0 = 0;
+
+       /* check if the demod is there */
+       ret = cx24110_readreg(state, 0x00);
+       if ((ret != 0x5a) && (ret != 0x69)) 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 cx24110_ops = {
+
+       .info = {
+               .name = "Conexant CX24110 DVB-S",
+               .type = FE_QPSK,
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+               .frequency_stepsize = 1011,  /* kHz for QPSK frontends */
+               .frequency_tolerance = 29500,
+               .symbol_rate_min = 1000000,
+               .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_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_RECOVER
+       },
+
+       .release = cx24110_release,
+
+       .init = cx24110_initfe,
+       .set_frontend = cx24110_set_frontend,
+       .get_frontend = cx24110_get_frontend,
+       .read_status = cx24110_read_status,
+       .read_ber = cx24110_read_ber,
+       .read_signal_strength = cx24110_read_signal_strength,
+       .read_snr = cx24110_read_snr,
+       .read_ucblocks = cx24110_read_ucblocks,
+
+       .diseqc_send_master_cmd = cx24110_send_diseqc_msg,
+       .set_tone = cx24110_set_tone,
+       .set_voltage = cx24110_set_voltage,
+};
 
-module_init(init_cx24110);
-module_exit(exit_cx24110);
-
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
-MODULE_DESCRIPTION("DVB Frontend driver module for the Conexant cx24108/cx24110 chipset");
+MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver");
 MODULE_AUTHOR("Peter Hettkamp");
 MODULE_LICENSE("GPL");
-MODULE_PARM(debug,"i");
 
+EXPORT_SYMBOL(cx24110_attach);
+EXPORT_SYMBOL(cx24110_pll_write);
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
index 6d9e610..b17a195 100644 (file)
  */    
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include "dvb_frontend.h"
+#include "dvb_dummy_fe.h"
 
-static int sct = 0;
-
-
-/* depending on module parameter sct deliver different infos
- */
-
-static struct dvb_frontend_info dvb_s_dummyfe_info = {
-       .name                   = "DVB-S dummy frontend",
-       .type                   = FE_QPSK,
-       .frequency_min          = 950000,
-       .frequency_max          = 2150000,
-       .frequency_stepsize     = 250,           /* kHz for QPSK frontends */
-       .frequency_tolerance    = 29500,
-       .symbol_rate_min        = 1000000,
-       .symbol_rate_max        = 45000000,
-/*      .symbol_rate_tolerance         = ???,*/
-       .notifier_delay          = 50,                /* 1/20 s */
-       .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
-};
 
-static struct dvb_frontend_info dvb_c_dummyfe_info = {
-       .name = "DVB-C dummy frontend",
-       .type = FE_QAM,
-       .frequency_stepsize = 62500,
-       .frequency_min = 51000000,
-       .frequency_max = 858000000,
-       .symbol_rate_min = (57840000/2)/64,     /* SACLK/64 == (XIN/2)/64 */
-       .symbol_rate_max = (57840000/2)/4,      /* SACLK/4 */
-#if 0
-       .frequency_tolerance    = ???,
-       .symbol_rate_tolerance  = ???,  /* ppm */  /* == 8% (spec p. 5) */
-       .notifier_delay         = ?,
-#endif
-       .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 | FE_CAN_INVERSION_AUTO
-};
 
-static struct dvb_frontend_info dvb_t_dummyfe_info = {
-       .name = "DVB-T dummy frontend",
-       .type = FE_OFDM,
-       .frequency_min = 0,
-       .frequency_max = 863250000,
-       .frequency_stepsize = 62500,
-       /*.frequency_tolerance = */     /* FIXME: 12% of SR */
-       .symbol_rate_min = 0,           /* FIXME */
-       .symbol_rate_max = 9360000,     /* FIXME */
-       .symbol_rate_tolerance = 4000,
-       .notifier_delay = 0,
-       .caps = 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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-                       FE_CAN_TRANSMISSION_MODE_AUTO |
-                       FE_CAN_GUARD_INTERVAL_AUTO |
-                       FE_CAN_HIERARCHY_AUTO,
-};
-
-struct dvb_frontend_info *frontend_info(void)
-{
-       switch(sct)
-       {
-       case 2:
-               return &dvb_t_dummyfe_info;
-       case 1:
-               return &dvb_c_dummyfe_info;
-       case 0:
-       default:
-               return &dvb_s_dummyfe_info;
-       }
-}
+struct dvb_dummy_fe_state {
 
+       struct dvb_frontend_ops ops;
 
-static int dvbdummyfe_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
-        switch (cmd) {
-        case FE_GET_INFO:
-               memcpy (arg, frontend_info(), 
-                       sizeof(struct dvb_frontend_info));
-               break;
+       struct dvb_frontend frontend;
+};
 
-        case FE_READ_STATUS:
+static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
        {
-               fe_status_t *status = arg;
                *status = FE_HAS_SIGNAL
                        | FE_HAS_CARRIER
                        | FE_HAS_VITERBI
                        | FE_HAS_SYNC
                        | FE_HAS_LOCK;
-               break;
+
+       return 0;
        }
 
-        case FE_READ_BER:
+static int dvb_dummy_fe_read_ber(struct dvb_frontend* fe, u32* ber)
        {
-               u32 *ber = (u32 *) arg;
                *ber = 0;
-               break;
+       return 0;
        }
 
-        case FE_READ_SIGNAL_STRENGTH:
+static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength)
        {
-               u8 signal = 0xff;
-               *((u16*) arg) = (signal << 8) | signal;
-               break;
+       *strength = 0;
+       return 0;
        }
 
-        case FE_READ_SNR:
+static int dvb_dummy_fe_read_snr(struct dvb_frontend* fe, u16* snr)
        {
-               u8 snr = 0xf0;
-               *(u16*) arg = (snr << 8) | snr;
-               break;
+       *snr = 0;
+       return 0;
        }
 
-       case FE_READ_UNCORRECTED_BLOCKS: 
-               *(u32*) arg = 0;
-               break;
-
-        case FE_SET_FRONTEND:
-                break;
-
-       case FE_GET_FRONTEND:
-               break;
-
-        case FE_SLEEP:
+static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       *ucblocks = 0;
                return 0;
+}
 
-        case FE_INIT:
+static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
                return 0;
+}
 
-       case FE_SET_TONE:
-               return -EOPNOTSUPP;
+static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       return 0;
+}
 
-       case FE_SET_VOLTAGE:
+static int dvb_dummy_fe_sleep(struct dvb_frontend* fe)
+{
                return 0;
+}
 
-       default:
-               return -EOPNOTSUPP;
+static int dvb_dummy_fe_init(struct dvb_frontend* fe)
+{
+       return 0;
         }
+
+static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
         return 0;
 } 
 
+static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+       return 0;
+}
 
-static int dvbdummyfe_attach (struct dvb_i2c_bus *i2c, void **data)
+static void dvb_dummy_fe_release(struct dvb_frontend* fe)
 {
-       return dvb_register_frontend (dvbdummyfe_ioctl, i2c, NULL, frontend_info());
+       struct dvb_dummy_fe_state* state = (struct dvb_dummy_fe_state*) fe->demodulator_priv;
+       kfree(state);
 }
 
+static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops;
 
-static void dvbdummyfe_detach (struct dvb_i2c_bus *i2c, void *data)
+struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
 {
-       dvb_unregister_frontend (dvbdummyfe_ioctl, i2c);
+       struct dvb_dummy_fe_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       memcpy(&state->ops, &dvb_dummy_fe_ofdm_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 dvb_dummy_fe_qpsk_ops;
 
-static int __init init_dvbdummyfe (void)
+struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
 {
-       return dvb_register_i2c_device (THIS_MODULE,
-                                       dvbdummyfe_attach, 
-                                       dvbdummyfe_detach);
+       struct dvb_dummy_fe_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       memcpy(&state->ops, &dvb_dummy_fe_qpsk_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 dvb_dummy_fe_qam_ops;
 
-static void __exit exit_dvbdummyfe (void)
+struct dvb_frontend* dvb_dummy_fe_qam_attach()
 {
-       dvb_unregister_i2c_device (dvbdummyfe_attach);
+       struct dvb_dummy_fe_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       memcpy(&state->ops, &dvb_dummy_fe_qam_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 dvb_dummy_fe_ofdm_ops = {
+
+       .info = {
+               .name                   = "Dummy DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 0,
+               .frequency_max          = 863250000,
+               .frequency_stepsize     = 62500,
+               .caps = 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_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 = dvb_dummy_fe_release,
+
+       .init = dvb_dummy_fe_init,
+       .sleep = dvb_dummy_fe_sleep,
+
+       .set_frontend = dvb_dummy_fe_set_frontend,
+       .get_frontend = dvb_dummy_fe_get_frontend,
+
+       .read_status = dvb_dummy_fe_read_status,
+       .read_ber = dvb_dummy_fe_read_ber,
+       .read_signal_strength = dvb_dummy_fe_read_signal_strength,
+       .read_snr = dvb_dummy_fe_read_snr,
+       .read_ucblocks = dvb_dummy_fe_read_ucblocks,
+};
 
-module_init(init_dvbdummyfe);
-module_exit(exit_dvbdummyfe);
+static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = {
+
+       .info = {
+               .name                   = "Dummy DVB-C",
+               .type                   = FE_QAM,
+               .frequency_stepsize     = 62500,
+               .frequency_min          = 51000000,
+               .frequency_max          = 858000000,
+               .symbol_rate_min        = (57840000/2)/64,     /* SACLK/64 == (XIN/2)/64 */
+               .symbol_rate_max        = (57840000/2)/4,      /* SACLK/4 */
+               .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 | FE_CAN_INVERSION_AUTO
+       },
+
+       .release = dvb_dummy_fe_release,
+
+       .init = dvb_dummy_fe_init,
+       .sleep = dvb_dummy_fe_sleep,
+
+       .set_frontend = dvb_dummy_fe_set_frontend,
+       .get_frontend = dvb_dummy_fe_get_frontend,
+
+       .read_status = dvb_dummy_fe_read_status,
+       .read_ber = dvb_dummy_fe_read_ber,
+       .read_signal_strength = dvb_dummy_fe_read_signal_strength,
+       .read_snr = dvb_dummy_fe_read_snr,
+       .read_ucblocks = dvb_dummy_fe_read_ucblocks,
+};
 
+static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = {
+
+       .info = {
+               .name                   = "Dummy DVB-S",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 250,           /* kHz for QPSK frontends */
+               .frequency_tolerance    = 29500,
+               .symbol_rate_min        = 1000000,
+               .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_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK
+       },
+
+       .release = dvb_dummy_fe_release,
+
+       .init = dvb_dummy_fe_init,
+       .sleep = dvb_dummy_fe_sleep,
+
+       .set_frontend = dvb_dummy_fe_set_frontend,
+       .get_frontend = dvb_dummy_fe_get_frontend,
+
+       .read_status = dvb_dummy_fe_read_status,
+       .read_ber = dvb_dummy_fe_read_ber,
+       .read_signal_strength = dvb_dummy_fe_read_signal_strength,
+       .read_snr = dvb_dummy_fe_read_snr,
+       .read_ucblocks = dvb_dummy_fe_read_ucblocks,
+
+       .set_voltage = dvb_dummy_fe_set_voltage,
+       .set_tone = dvb_dummy_fe_set_tone,
+};
 
 MODULE_DESCRIPTION("DVB DUMMY Frontend");
 MODULE_AUTHOR("Emard");
 MODULE_LICENSE("GPL");
-MODULE_PARM(sct, "i");
+
+EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach);
+EXPORT_SYMBOL(dvb_dummy_fe_qam_attach);
+EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach);
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
index b3d5ddf..a5dcc87 100644 (file)
@@ -1,5 +1,5 @@
 /* 
-    Driver for Zarlink MT312 Satellite Channel Decoder
+    Driver for Zarlink VP310/MT312 Satellite Channel Decoder
 
     Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
 
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 
 #include "dvb_frontend.h"
+#include "mt312_priv.h"
 #include "mt312.h"
 
-#define I2C_ADDR_MT312         0x0e
-#define I2C_ADDR_SL1935                0x61
-#define I2C_ADDR_TSA5059       0x61
 
-#define MT312_DEBUG            0
+struct mt312_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       /* configuration settings */
+       const struct mt312_config* config;
+
+       struct dvb_frontend frontend;
+
+       u8 id;
+       u8 frequency;
+};
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "mt312: " args); \
+       } while (0)
 
 #define MT312_SYS_CLK          90000000UL      /* 90 MHz */
 #define MT312_LPOWER_SYS_CLK   60000000UL      /* 60 MHz */
 #define MT312_PLL_CLK          10000000UL      /* 10 MHz */
 
-/* number of active frontends */
-static int mt312_count = 0;
-
-#if MT312_DEBUG == 0
-#define dprintk(x...)
-#else
-static int debug = 0;
-#define dprintk if(debug == 1) printk
-#endif
-
-static struct dvb_frontend_info mt312_info = {
-       .name = "Zarlink MT312",
-       .type = FE_QPSK,
-       .frequency_min = 950000,
-       .frequency_max = 2150000,
-       .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
-       /*.frequency_tolerance = 29500,         FIXME: binary compatibility waste? */
-       .symbol_rate_min = MT312_SYS_CLK / 128,
-       .symbol_rate_max = MT312_SYS_CLK / 2,
-       /*.symbol_rate_tolerance = 500,         FIXME: binary compatibility waste? 2% */
-       .notifier_delay = 0,
-       .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_MUTE_TS | 
-            FE_CAN_RECOVER
-};
-
-static int mt312_read(struct dvb_i2c_bus *i2c,
-                     const enum mt312_reg_addr reg, void *buf,
-                     const size_t count)
+static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
+                     void *buf, const size_t count)
 {
        int ret;
        struct i2c_msg msg[2];
        u8 regbuf[1] = { reg };
 
-       msg[0].addr = I2C_ADDR_MT312;
+       msg[0].addr = state->config->demod_address;
        msg[0].flags = 0;
        msg[0].buf = regbuf;
        msg[0].len = 1;
-       msg[1].addr = I2C_ADDR_MT312;
+       msg[1].addr = state->config->demod_address;
        msg[1].flags = I2C_M_RD;
        msg[1].buf = buf;
        msg[1].len = count;
 
-       ret = i2c->xfer(i2c, msg, 2);
+       ret = i2c_transfer(state->i2c, msg, 2);
 
-       if ((ret != 2) && (mt312_count != 0)) {
+       if (ret != 2) {
                printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret);
                return -EREMOTEIO;
        }
-#if MT312_DEBUG
+
        if(debug) {
                int i;
-               printk(KERN_INFO "R(%d):", reg & 0x7f);
+               dprintk("R(%d):", reg & 0x7f);
                for (i = 0; i < count; i++)
                        printk(" %02x", ((const u8 *) buf)[i]);
                printk("\n");
        }
-#endif
 
        return 0;
 }
 
-static int mt312_write(struct dvb_i2c_bus *i2c,
-                      const enum mt312_reg_addr reg, const void *src,
-                      const size_t count)
+static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
+                      const void *src, const size_t count)
 {
        int ret;
        u8 buf[count + 1];
        struct i2c_msg msg;
 
-#if MT312_DEBUG
        if(debug) {
                int i;
-               printk(KERN_INFO "W(%d):", reg & 0x7f);
+               dprintk("W(%d):", reg & 0x7f);
                for (i = 0; i < count; i++)
                        printk(" %02x", ((const u8 *) src)[i]);
                printk("\n");
        }
-#endif
 
        buf[0] = reg;
        memcpy(&buf[1], src, count);
 
-       msg.addr = I2C_ADDR_MT312;
+       msg.addr = state->config->demod_address;
        msg.flags = 0;
        msg.buf = buf;
        msg.len = count + 1;
 
-       ret = i2c->xfer(i2c, &msg, 1);
+       ret = i2c_transfer(state->i2c, &msg, 1);
 
        if (ret != 1) {
-               printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret);
+               dprintk("%s: ret == %d\n", __FUNCTION__, ret);
                return -EREMOTEIO;
        }
 
        return 0;
 }
 
-static inline int mt312_readreg(struct dvb_i2c_bus *i2c,
+static inline int mt312_readreg(struct mt312_state* state,
                                const enum mt312_reg_addr reg, u8 * val)
 {
-       return mt312_read(i2c, reg, val, 1);
+       return mt312_read(state, reg, val, 1);
 }
 
-static inline int mt312_writereg(struct dvb_i2c_bus *i2c,
+static inline int mt312_writereg(struct mt312_state* state,
                                 const enum mt312_reg_addr reg, const u8 val)
 {
-       return mt312_write(i2c, reg, &val, 1);
+       return mt312_write(state, reg, &val, 1);
 }
 
-static int mt312_pll_write(struct dvb_i2c_bus *i2c, const u8 addr,
-                          u8 * buf, const u8 len)
+static inline u32 mt312_div(u32 a, u32 b)
+{
+       return (a + (b / 2)) / b;
+}
+
+static int mt312_reset(struct mt312_state* state, const u8 full)
+{
+       return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
+}
+
+static int mt312_get_inversion(struct mt312_state* state,
+                              fe_spectral_inversion_t *i)
 {
        int ret;
-       struct i2c_msg msg;
+       u8 vit_mode;
 
-       msg.addr = addr;
-       msg.flags = 0;
-       msg.buf = buf;
-       msg.len = len;
+       if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0)
+               return ret;
 
-       if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x40)) < 0)
+       if (vit_mode & 0x80)    /* auto inversion was used */
+               *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
+
+       return 0;
+}
+
+static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
+{
+       int ret;
+       u8 sym_rate_h;
+       u8 dec_ratio;
+       u16 sym_rat_op;
+       u16 monitor;
+       u8 buf[2];
+
+       if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0)
                return ret;
 
-       if ((ret = i2c->xfer(i2c, &msg, 1)) != 1)
-               printk(KERN_ERR "%s: i/o error (ret == %d)\n", __FUNCTION__, ret);
+       if (sym_rate_h & 0x80) {        /* symbol rate search was used */
+               if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0)
+                       return ret;
 
-       if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x00)) < 0)
+               if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
                return ret;
 
-       return 0;
+               monitor = (buf[0] << 8) | buf[1];
+
+               dprintk(KERN_DEBUG "sr(auto) = %u\n",
+                      mt312_div(monitor * 15625, 4));
+       } else {
+               if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0)
+                       return ret;
+
+               if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
+                       return ret;
+
+               dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
+
+               if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
+                       return ret;
+
+               sym_rat_op = (buf[0] << 8) | buf[1];
+
+               dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
+                      sym_rat_op, dec_ratio);
+               dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
+                      (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
+                       2) - dec_ratio);
 }
 
-static inline u32 mt312_div(u32 a, u32 b)
-{
-       return (a + (b / 2)) / b;
+       return 0;
 }
 
-static int sl1935_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq, u32 sr)
+static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
 {
-       /* 155 uA, Baseband Path B */
-       u8 buf[4] = { 0x00, 0x00, 0x80, 0x00 };
-
-       u8 exp;
-       u32 ref;
-       u32 div;
-
-       if (sr < 10000000) {    /* 1-10 MSym/s: ratio 2 ^ 3 */
-               exp = 3;
-               buf[2] |= 0x40; /* 690 uA */
-       } else if (sr < 15000000) {     /* 10-15 MSym/s: ratio 2 ^ 4 */
-               exp = 4;
-               buf[2] |= 0x20; /* 330 uA */
-       } else {                /* 15-45 MSym/s: ratio 2 ^ 7 */
-               exp = 7;
-               buf[3] |= 0x08; /* Baseband Path A */
+       const fe_code_rate_t fec_tab[8] =
+           { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
+               FEC_AUTO, FEC_AUTO };
+
+       int ret;
+       u8 fec_status;
+
+       if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0)
+               return ret;
+
+       *cr = fec_tab[(fec_status >> 4) & 0x07];
+
+       return 0;
        }
 
-       div = mt312_div(MT312_PLL_CLK, 1 << exp);
-       ref = mt312_div(freq * 1000, div);
-       mt312_info.frequency_stepsize = mt312_div(div, 1000);
 
-       buf[0] = (ref >> 8) & 0x7f;
-       buf[1] = (ref >> 0) & 0xff;
-       buf[2] |= (exp - 1);
 
-       if (freq < 1550000)
-               buf[3] |= 0x10;
 
-       dprintk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0],
-              buf[1], buf[2], buf[3]);
 
-       return mt312_pll_write(i2c, I2C_ADDR_SL1935, buf, sizeof(buf));
-}
 
-static int tsa5059_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq, u32 sr)
-{
-       u8 buf[4];
 
-       u32 ref = mt312_div(freq, 125);
 
-       buf[0] = (ref >> 8) & 0x7f;
-       buf[1] = (ref >> 0) & 0xff;
-       buf[2] = 0x84 | ((ref >> 10) & 0x60);
-       buf[3] = 0x80;
        
-       if (freq < 1550000)
-               buf[3] |= 0x02;
 
-       dprintk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0],
-              buf[1], buf[2], buf[3]);
 
-       return mt312_pll_write(i2c, I2C_ADDR_TSA5059, buf, sizeof(buf));
-}
 
-static int mt312_reset(struct dvb_i2c_bus *i2c, const u8 full)
-{
-       return mt312_writereg(i2c, RESET, full ? 0x80 : 0x40);
-}
 
-static int mt312_init(struct dvb_i2c_bus *i2c, const long id, u8 pll)
+
+
+static int mt312_initfe(struct dvb_frontend* fe)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
        u8 buf[2];
 
        /* wake up */
-       if ((ret = mt312_writereg(i2c, CONFIG, (pll == 60 ? 0x88 : 0x8c))) < 0)
+       if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0)
                return ret;
 
        /* wait at least 150 usec */
        udelay(150);
 
        /* full reset */
-       if ((ret = mt312_reset(i2c, 1)) < 0)
+       if ((ret = mt312_reset(state, 1)) < 0)
                return ret;
 
 // Per datasheet, write correct values. 09/28/03 ACCJr.
@@ -265,56 +264,63 @@ static int mt312_init(struct dvb_i2c_bus *i2c, const long id, u8 pll)
        {
                u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00};
 
-               if ((ret = mt312_write(i2c, VIT_SETUP, buf_def, sizeof(buf_def))) < 0)
+               if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0)
                        return ret;
        }
 
        /* SYS_CLK */
-       buf[0] = mt312_div((pll == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000);
+       buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000);
 
        /* DISEQC_RATIO */
        buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
 
-       if ((ret = mt312_write(i2c, SYS_CLK, buf, sizeof(buf))) < 0)
+       if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0)
                return ret;
 
-       if ((ret = mt312_writereg(i2c, SNR_THS_HIGH, 0x32)) < 0)
+       if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0)
                return ret;
 
-       if ((ret = mt312_writereg(i2c, OP_CTRL, 0x53)) < 0)
+       if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0)
                return ret;
 
        /* TS_SW_LIM */
        buf[0] = 0x8c;
        buf[1] = 0x98;
 
-       if ((ret = mt312_write(i2c, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
+       if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
                return ret;
 
-       if ((ret = mt312_writereg(i2c, CS_SW_LIM, 0x69)) < 0)
+       if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
                return ret;
 
+       if (state->config->pll_init) {
+               mt312_writereg(state, GPP_CTRL, 0x40);
+               state->config->pll_init(fe);
+               mt312_writereg(state, GPP_CTRL, 0x00);
+       }
+
        return 0;
 }
 
-static int mt312_send_master_cmd(struct dvb_i2c_bus *i2c,
-                                const struct dvb_diseqc_master_cmd *c)
+static int mt312_send_master_cmd(struct dvb_frontend* fe,
+                                struct dvb_diseqc_master_cmd *c)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
        u8 diseqc_mode;
 
        if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
                return -EINVAL;
 
-       if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0)
+       if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
                return ret;
 
        if ((ret =
-            mt312_write(i2c, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
+            mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
                return ret;
 
        if ((ret =
-            mt312_writereg(i2c, DISEQC_MODE,
+            mt312_writereg(state, DISEQC_MODE,
                            (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
                            | 0x04)) < 0)
                return ret;
@@ -322,21 +328,15 @@ static int mt312_send_master_cmd(struct dvb_i2c_bus *i2c,
        /* set DISEQC_MODE[2:0] to zero if a return message is expected */
        if (c->msg[0] & 0x02)
                if ((ret =
-                    mt312_writereg(i2c, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
+                    mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
                        return ret;
 
        return 0;
 }
 
-static int mt312_recv_slave_reply(struct dvb_i2c_bus *i2c,
-                                 struct dvb_diseqc_slave_reply *r)
-{
-       /* TODO */
-       return -EOPNOTSUPP;
-}
-
-static int mt312_send_burst(struct dvb_i2c_bus *i2c, const fe_sec_mini_cmd_t c)
+static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        const u8 mini_tab[2] = { 0x02, 0x03 };
 
        int ret;
@@ -345,19 +345,20 @@ static int mt312_send_burst(struct dvb_i2c_bus *i2c, const fe_sec_mini_cmd_t c)
        if (c > SEC_MINI_B)
                return -EINVAL;
 
-       if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0)
+       if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
                return ret;
 
        if ((ret =
-            mt312_writereg(i2c, DISEQC_MODE,
+            mt312_writereg(state, DISEQC_MODE,
                            (diseqc_mode & 0x40) | mini_tab[c])) < 0)
                return ret;
 
        return 0;
 }
 
-static int mt312_set_tone(struct dvb_i2c_bus *i2c, const fe_sec_tone_mode_t t)
+static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        const u8 tone_tab[2] = { 0x01, 0x00 };
 
        int ret;
@@ -366,35 +367,37 @@ static int mt312_set_tone(struct dvb_i2c_bus *i2c, const fe_sec_tone_mode_t t)
        if (t > SEC_TONE_OFF)
                return -EINVAL;
 
-       if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0)
+       if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
                return ret;
 
        if ((ret =
-            mt312_writereg(i2c, DISEQC_MODE,
+            mt312_writereg(state, DISEQC_MODE,
                            (diseqc_mode & 0x40) | tone_tab[t])) < 0)
                return ret;
 
        return 0;
 }
 
-static int mt312_set_voltage(struct dvb_i2c_bus *i2c, const fe_sec_voltage_t v)
+static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
 
        if (v > SEC_VOLTAGE_OFF)
                return -EINVAL;
 
-       return mt312_writereg(i2c, DISEQC_MODE, volt_tab[v]);
+       return mt312_writereg(state, DISEQC_MODE, volt_tab[v]);
 }
 
-static int mt312_read_status(struct dvb_i2c_bus *i2c, fe_status_t *s, const long id)
+static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
-       u8 status[3], vit_mode;
+       u8 status[3];
 
        *s = 0;
 
-       if ((ret = mt312_read(i2c, QPSK_STAT_H, status, sizeof(status))) < 0)
+       if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0)
                return ret;
 
        dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
@@ -409,26 +412,17 @@ static int mt312_read_status(struct dvb_i2c_bus *i2c, fe_status_t *s, const long
                *s |= FE_HAS_SYNC;      /* byte align lock */
        if (status[0] & 0x01)
                *s |= FE_HAS_LOCK;      /* qpsk lock */
-       // VP310 doesn't have AUTO, so we "implement it here" ACCJr
-       if ((id == ID_VP310) && !(status[0] & 0x01)) {
-               if ((ret = mt312_readreg(i2c, VIT_MODE, &vit_mode)) < 0)
-                       return ret;
-               vit_mode ^= 0x40;
-               if ((ret = mt312_writereg(i2c, VIT_MODE, vit_mode)) < 0)
-                       return ret;
-               if ((ret = mt312_writereg(i2c, GO, 0x01)) < 0)
-                       return ret;
-       }
 
        return 0;
 }
 
-static int mt312_read_bercnt(struct dvb_i2c_bus *i2c, u32 * ber)
+static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
        u8 buf[3];
 
-       if ((ret = mt312_read(i2c, RS_BERCNT_H, buf, 3)) < 0)
+       if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0)
                return ret;
 
        *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
@@ -436,14 +430,15 @@ static int mt312_read_bercnt(struct dvb_i2c_bus *i2c, u32 * ber)
        return 0;
 }
 
-static int mt312_read_agc(struct dvb_i2c_bus *i2c, u16 * signal_strength)
+static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
        u8 buf[3];
        u16 agc;
        s16 err_db;
 
-       if ((ret = mt312_read(i2c, AGC_H, buf, sizeof(buf))) < 0)
+       if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0)
                return ret;
 
        agc = (buf[0] << 6) | (buf[1] >> 2);
@@ -456,12 +451,13 @@ static int mt312_read_agc(struct dvb_i2c_bus *i2c, u16 * signal_strength)
        return 0;
 }
 
-static int mt312_read_snr(struct dvb_i2c_bus *i2c, u16 * snr)
+static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
        u8 buf[2];
 
-       if ((ret = mt312_read(i2c, M_SNR_H, &buf, sizeof(buf))) < 0)
+       if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0)
                return ret;
 
        *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
@@ -469,12 +465,13 @@ static int mt312_read_snr(struct dvb_i2c_bus *i2c, u16 * snr)
        return 0;
 }
 
-static int mt312_read_ubc(struct dvb_i2c_bus *i2c, u32 * ubc)
+static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
        u8 buf[2];
 
-       if ((ret = mt312_read(i2c, RS_UBC_H, &buf, sizeof(buf))) < 0)
+       if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0)
                return ret;
 
        *ubc = (buf[0] << 8) | buf[1];
@@ -482,10 +479,10 @@ static int mt312_read_ubc(struct dvb_i2c_bus *i2c, u32 * ubc)
        return 0;
 }
 
-static int mt312_set_frontend(struct dvb_i2c_bus *i2c,
-                             const struct dvb_frontend_parameters *p,
-                             const long id)
+static int mt312_set_frontend(struct dvb_frontend* fe,
+                             struct dvb_frontend_parameters *p)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
        u8 buf[5], config_val;
        u16 sr;
@@ -494,20 +491,18 @@ static int mt312_set_frontend(struct dvb_i2c_bus *i2c,
            { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
        const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
 
-       int (*set_tv_freq)(struct dvb_i2c_bus *i2c, u32 freq, u32 sr);
-
        dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
 
-       if ((p->frequency < mt312_info.frequency_min)
-           || (p->frequency > mt312_info.frequency_max))
+       if ((p->frequency < fe->ops->info.frequency_min)
+           || (p->frequency > fe->ops->info.frequency_max))
                return -EINVAL;
 
        if ((p->inversion < INVERSION_OFF)
-           || (p->inversion > INVERSION_AUTO))
+           || (p->inversion > INVERSION_ON))
                return -EINVAL;
 
-       if ((p->u.qpsk.symbol_rate < mt312_info.symbol_rate_min)
-           || (p->u.qpsk.symbol_rate > mt312_info.symbol_rate_max))
+       if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min)
+           || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max))
                return -EINVAL;
 
        if ((p->u.qpsk.fec_inner < FEC_NONE)
@@ -518,35 +513,40 @@ static int mt312_set_frontend(struct dvb_i2c_bus *i2c,
            || (p->u.qpsk.fec_inner == FEC_8_9))
                return -EINVAL;
 
-       switch (id) {
+       switch (state->id) {
        case ID_VP310:
        // For now we will do this only for the VP310.
        // It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
-               if ((ret = mt312_readreg(i2c, CONFIG, &config_val) < 0))
+               if ((ret = mt312_readreg(state, CONFIG, &config_val) < 0))
                        return ret;
                if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
                {
-                       if ((config_val & 0x0c) == 0x08) //We are running 60MHz
-                               if ((ret = mt312_init(i2c, id, (u8) 90)) < 0)
+                       if ((config_val & 0x0c) == 0x08) { //We are running 60MHz
+                               state->frequency = 90;
+                               if ((ret = mt312_initfe(fe)) < 0)
                                        return ret;
                }
+               }
                else
                {
-                       if ((config_val & 0x0c) == 0x0C) //We are running 90MHz
-                               if ((ret = mt312_init(i2c, id, (u8) 60)) < 0)
+                       if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz
+                               state->frequency = 60;
+                               if ((ret = mt312_initfe(fe)) < 0)
                                        return ret;
                }
-               set_tv_freq = tsa5059_set_tv_freq;
+               }
                break;
+
        case ID_MT312:
-               set_tv_freq = sl1935_set_tv_freq;
                break;
+
        default:
                return -EINVAL;
        }
 
-       if ((ret = set_tv_freq(i2c, p->frequency, p->u.qpsk.symbol_rate)) < 0)
-               return ret;
+       mt312_writereg(state, GPP_CTRL, 0x40);
+       state->config->pll_set(fe, p);
+       mt312_writereg(state, GPP_CTRL, 0x00);
 
        /* sr = (u16)(sr * 256.0 / 1000000.0) */
        sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
@@ -567,259 +567,182 @@ static int mt312_set_frontend(struct dvb_i2c_bus *i2c,
        /* GO */
        buf[4] = 0x01;
 
-       if ((ret = mt312_write(i2c, SYM_RATE_H, buf, sizeof(buf))) < 0)
-               return ret;
-
-        mt312_reset(i2c, 0);
-
-       return 0;
-}
-
-static int mt312_get_inversion(struct dvb_i2c_bus *i2c,
-                              fe_spectral_inversion_t * i)
-{
-       int ret;
-       u8 vit_mode;
-
-       if ((ret = mt312_readreg(i2c, VIT_MODE, &vit_mode)) < 0)
+       if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0)
                return ret;
 
-       if (vit_mode & 0x80)    /* auto inversion was used */
-               *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
+        mt312_reset(state, 0);
 
        return 0;
 }
 
-static int mt312_get_symbol_rate(struct dvb_i2c_bus *i2c, u32 * sr)
-{
-       int ret;
-       u8 sym_rate_h;
-       u8 dec_ratio;
-       u16 sym_rat_op;
-       u16 monitor;
-       u8 buf[2];
-
-       if ((ret = mt312_readreg(i2c, SYM_RATE_H, &sym_rate_h)) < 0)
-               return ret;
-
-       if (sym_rate_h & 0x80) {        /* symbol rate search was used */
-               if ((ret = mt312_writereg(i2c, MON_CTRL, 0x03)) < 0)
-                       return ret;
-
-               if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0)
-                       return ret;
-
-               monitor = (buf[0] << 8) | buf[1];
-
-               dprintk(KERN_DEBUG "sr(auto) = %u\n",
-                      mt312_div(monitor * 15625, 4));
-       } else {
-               if ((ret = mt312_writereg(i2c, MON_CTRL, 0x05)) < 0)
-                       return ret;
-
-               if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0)
-                       return ret;
-
-               dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
-
-               if ((ret = mt312_read(i2c, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
-                       return ret;
-
-               sym_rat_op = (buf[0] << 8) | buf[1];
-
-               dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
-                      sym_rat_op, dec_ratio);
-               dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
-                      (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
-                       2) - dec_ratio);
-       }
-
-       return 0;
-}
-
-static int mt312_get_code_rate(struct dvb_i2c_bus *i2c, fe_code_rate_t * cr)
-{
-       const fe_code_rate_t fec_tab[8] =
-           { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
-               FEC_AUTO, FEC_AUTO };
-
-       int ret;
-       u8 fec_status;
-
-       if ((ret = mt312_readreg(i2c, FEC_STATUS, &fec_status)) < 0)
-               return ret;
-
-       *cr = fec_tab[(fec_status >> 4) & 0x07];
-
-       return 0;
-}
-
-static int mt312_get_frontend(struct dvb_i2c_bus *i2c,
+static int mt312_get_frontend(struct dvb_frontend* fe,
                              struct dvb_frontend_parameters *p)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
 
-       if ((ret = mt312_get_inversion(i2c, &p->inversion)) < 0)
+       if ((ret = mt312_get_inversion(state, &p->inversion)) < 0)
                return ret;
 
-       if ((ret = mt312_get_symbol_rate(i2c, &p->u.qpsk.symbol_rate)) < 0)
+       if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0)
                return ret;
 
-       if ((ret = mt312_get_code_rate(i2c, &p->u.qpsk.fec_inner)) < 0)
+       if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0)
                return ret;
 
        return 0;
 }
 
-static int mt312_sleep(struct dvb_i2c_bus *i2c)
+static int mt312_sleep(struct dvb_frontend* fe)
 {
+       struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
        int ret;
        u8 config;
 
        /* reset all registers to defaults */
-       if ((ret = mt312_reset(i2c, 1)) < 0)
+       if ((ret = mt312_reset(state, 1)) < 0)
                return ret;
 
-       if ((ret = mt312_readreg(i2c, CONFIG, &config)) < 0)
+       if ((ret = mt312_readreg(state, CONFIG, &config)) < 0)
                return ret;
 
        /* enter standby */
-       if ((ret = mt312_writereg(i2c, CONFIG, config & 0x7f)) < 0)
+       if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0)
                return ret;
 
        return 0;
 }
 
-static int mt312_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
-       struct dvb_i2c_bus *i2c = fe->i2c;
-
-       switch (cmd) {
-       case FE_GET_INFO:
-               memcpy(arg, &mt312_info, sizeof(struct dvb_frontend_info));
-               break;
-
-       case FE_DISEQC_RESET_OVERLOAD:
-               return -EOPNOTSUPP;
-
-       case FE_DISEQC_SEND_MASTER_CMD:
-               return mt312_send_master_cmd(i2c, arg);
-
-       case FE_DISEQC_RECV_SLAVE_REPLY:
-               if ((long) fe->data == ID_MT312)
-                       return mt312_recv_slave_reply(i2c, arg);
-               else
-                       return -EOPNOTSUPP;
-
-       case FE_DISEQC_SEND_BURST:
-               return mt312_send_burst(i2c, (fe_sec_mini_cmd_t) arg);
-
-       case FE_SET_TONE:
-               return mt312_set_tone(i2c, (fe_sec_tone_mode_t) arg);
-
-       case FE_SET_VOLTAGE:
-               return mt312_set_voltage(i2c, (fe_sec_voltage_t) arg);
-
-       case FE_ENABLE_HIGH_LNB_VOLTAGE:
-               return -EOPNOTSUPP;
-
-       case FE_READ_STATUS:
-               return mt312_read_status(i2c, arg, (long) fe->data);
-
-       case FE_READ_BER:
-               return mt312_read_bercnt(i2c, arg);
-
-       case FE_READ_SIGNAL_STRENGTH:
-               return mt312_read_agc(i2c, arg);
-
-       case FE_READ_SNR:
-               return mt312_read_snr(i2c, arg);
-
-       case FE_READ_UNCORRECTED_BLOCKS:
-               return mt312_read_ubc(i2c, arg);
-
-       case FE_SET_FRONTEND:
-               return mt312_set_frontend(i2c, arg, (long) fe->data);
-
-       case FE_GET_FRONTEND:
-               return mt312_get_frontend(i2c, arg);
-
-       case FE_GET_EVENT:
-               return -EOPNOTSUPP;
-
-       case FE_SLEEP:
-               return mt312_sleep(i2c);
-
-       case FE_INIT:
-       //For the VP310 we should run at 60MHz when ever possible.
-       //It should be better to run the mt312 ar lower speed when ever possible, but tunning will be slower. ACCJr 09/29/03
-               if ((long)fe->data == ID_MT312)
-                       return mt312_init(i2c, (long) fe->data, (u8) 90);
-               else
-                       return mt312_init(i2c, (long) fe->data, (u8) 60);
-
-       case FE_GET_TUNE_SETTINGS:
+static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
        {
-               struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
                fesettings->min_delay_ms = 50;
                fesettings->step_size = 0;
                fesettings->max_drift = 0;
                return 0;
        }           
 
-       default:
-               return -ENOIOCTLCMD;
-       }
-
-       return 0;
-}
-
-static int mt312_attach(struct dvb_i2c_bus *i2c, void **data)
+static void mt312_release(struct dvb_frontend* fe)
 {
-       int ret;
-       u8 id;
-
-       if ((ret = mt312_readreg(i2c, ID, &id)) < 0)
-               return ret;
+       struct mt312_state* state = (struct mt312_state*) fe->demodulator_priv;
+       kfree(state);
+}
 
-       if ((id != ID_VP310) && (id != ID_MT312))
-               return -ENODEV;
+static struct dvb_frontend_ops vp310_mt312_ops;
 
-       if ((ret = dvb_register_frontend(mt312_ioctl, i2c,
-                               (void *)(long)id, &mt312_info)) < 0)
-               return ret;
+struct dvb_frontend* vp310_attach(const struct mt312_config* config,
+                                 struct i2c_adapter* i2c)
+{
+       struct mt312_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+       strcpy(state->ops.info.name, "Zarlink VP310 DVB-S");
+
+       /* check if the demod is there */
+       if (mt312_readreg(state, ID, &state->id) < 0)
+               goto error;
+       if (state->id != ID_VP310) {
+               goto error;
+       }
 
-       mt312_count++;
+       /* create dvb_frontend */
+               state->frequency = 90;
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
 
-       return 0;
+error:
+       if (state)
+               kfree(state);
+       return NULL;
 }
 
-static void mt312_detach(struct dvb_i2c_bus *i2c, void *data)
+struct dvb_frontend* mt312_attach(const struct mt312_config* config,
+                                 struct i2c_adapter* i2c)
 {
-       dvb_unregister_frontend(mt312_ioctl, i2c);
-
-       if (mt312_count)
-               mt312_count--;
+       struct mt312_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+       strcpy(state->ops.info.name, "Zarlink MT312 DVB-S");
+
+       /* check if the demod is there */
+       if (mt312_readreg(state, ID, &state->id) < 0)
+               goto error;
+       if (state->id != ID_MT312) {
+               goto error;
 }
 
-static int __init mt312_module_init(void)
-{
-       return dvb_register_i2c_device(THIS_MODULE, mt312_attach, mt312_detach);
-}
+       /* create dvb_frontend */
+       state->frequency = 60;
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
 
-static void __exit mt312_module_exit(void)
-{
-       dvb_unregister_i2c_device(mt312_attach);
+error:
+       if (state)
+               kfree(state);
+       return NULL;
 }
 
-module_init(mt312_module_init);
-module_exit(mt312_module_exit);
+static struct dvb_frontend_ops vp310_mt312_ops = {
+
+       .info = {
+               .name = "Zarlink ???? DVB-S",
+               .type = FE_QPSK,
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+               .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
+               .symbol_rate_min = MT312_SYS_CLK / 128,
+               .symbol_rate_max = MT312_SYS_CLK / 2,
+               .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_MUTE_TS |
+                   FE_CAN_RECOVER
+       },
+
+       .release = mt312_release,
+
+       .init = mt312_initfe,
+       .sleep = mt312_sleep,
+
+       .set_frontend = mt312_set_frontend,
+       .get_frontend = mt312_get_frontend,
+       .get_tune_settings = mt312_get_tune_settings,
+
+       .read_status = mt312_read_status,
+       .read_ber = mt312_read_ber,
+       .read_signal_strength = mt312_read_signal_strength,
+       .read_snr = mt312_read_snr,
+       .read_ucblocks = mt312_read_ucblocks,
+
+       .diseqc_send_master_cmd = mt312_send_master_cmd,
+       .diseqc_send_burst = mt312_send_burst,
+       .set_tone = mt312_set_tone,
+       .set_voltage = mt312_set_voltage,
+};
 
-#if MT312_DEBUG != 0
-MODULE_PARM(debug,"i");
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-#endif
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
-MODULE_DESCRIPTION("MT312 Satellite Channel Decoder Driver");
+MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
 MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(mt312_attach);
+EXPORT_SYMBOL(vp310_attach);
index 222c6ec..1f58f0c 100644 (file)
@@ -1,5 +1,5 @@
 /* 
-    Driver for Zarlink MT312 QPSK Frontend
+    Driver for Zarlink MT312 Satellite Channel Decoder
 
     Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
 
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
+    References:
+    http://products.zarlink.com/product_profiles/MT312.htm
+    http://products.zarlink.com/product_profiles/SL1935.htm
 */
 
-#ifndef _DVB_FRONTENDS_MT312
-#define _DVB_FRONTENDS_MT312
+#ifndef MT312_H
+#define MT312_H
 
-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
-};
+#include <linux/dvb/frontend.h>
+
+struct mt312_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
 
-enum mt312_model_id {
-       ID_VP310 = 1,
-       ID_MT312 = 3
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
-#endif                         /* DVB_FRONTENDS_MT312 */
+extern struct dvb_frontend* mt312_attach(const struct mt312_config* config,
+                                        struct i2c_adapter* i2c);
+
+extern struct dvb_frontend* vp310_attach(const struct mt312_config* config,
+                                        struct i2c_adapter* i2c);
+
+#endif // MT312_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_ */
index 7116b0b..a55fd99 100644 (file)
@@ -1,13 +1,6 @@
 /* 
-
        NxtWave Communications - NXT6000 demodulator driver
        
-       This driver currently supports:
-       
-       Alps TDME7 (Tuner: MITEL SP5659)
-       Alps TDED4 (Tuner: TI ALP510, external Nxt6000)
-       Comtech DVBT-6k07 (PLL IC: SP5730)
-
     Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
     Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
 
 #include <linux/slab.h>
 
 #include "dvb_frontend.h"
+#include "nxt6000_priv.h"
 #include "nxt6000.h"
 
-static int debug = 0;
 
-MODULE_DESCRIPTION("NxtWave NXT6000 DVB demodulator driver");
-MODULE_AUTHOR("Florian Schirmer");
-MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
-
-static struct dvb_frontend_info nxt6000_info = {
-
-       .name = "NxtWave NXT6000",
-       .type = FE_OFDM,
-       .frequency_min = 0,
-       .frequency_max = 863250000,
-       .frequency_stepsize = 62500,
-       /*.frequency_tolerance = */     /* FIXME: 12% of SR */
-       .symbol_rate_min = 0,           /* FIXME */
-       .symbol_rate_max = 9360000,     /* FIXME */
-       .symbol_rate_tolerance = 4000,
-       .notifier_delay = 0,
-       .caps = 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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 
-                FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | 
-                FE_CAN_HIERARCHY_AUTO,
-};
 
-struct nxt6000_config {
-       u8 demod_addr;
-       u8 tuner_addr;
-       u8 tuner_type;
-       u8 clock_inversion;
-};
+struct nxt6000_state {
+
+       struct i2c_adapter *i2c;
 
-#define TUNER_TYPE_ALP510      0
-#define TUNER_TYPE_SP5659      1
-#define TUNER_TYPE_SP5730      2
+       struct dvb_frontend_ops ops;
 
-#define FE2NXT(fe) ((struct nxt6000_config *)((fe)->data))
-#define FREQ2DIV(freq) ((freq + 36166667) / 166667)
+       /* configuration settings */
+       const struct nxt6000_config* config;
+
+       struct dvb_frontend frontend;
+
+};
 
+static int debug = 0;
 #define dprintk if (debug) printk
 
-static int nxt6000_write(struct dvb_i2c_bus *i2c, u8 addr, u8 reg, u8 data)
+static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data)
 {
-
        u8 buf[] = {reg, data};
-       struct i2c_msg msg = {.addr = addr >> 1, .flags = 0, .buf = buf, .len = 2};
+       struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 };
        int ret;
        
-       if ((ret = i2c->xfer(i2c, &msg, 1)) != 1)
-               dprintk("nxt6000: nxt6000_write error (.addr = 0x%02X, reg: 0x%02X, data: 0x%02X, ret: %d)\n", addr, reg, data, ret);
+       if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
+               dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret);
 
        return (ret != 1) ? -EFAULT : 0;
-       
 }
 
-static u8 nxt6000_writereg(struct dvb_frontend *fe, u8 reg, u8 data)
+static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg)
 {
-
-       struct nxt6000_config *nxt = FE2NXT(fe);
-
-       return nxt6000_write(fe->i2c, nxt->demod_addr, reg, data);
-
-}
-
-static u8 nxt6000_read(struct dvb_i2c_bus *i2c, u8 addr, u8 reg)
-{
-
        int ret;
        u8 b0[] = {reg};
        u8 b1[] = {0};
        struct i2c_msg msgs[] = {
-               {.addr = addr >> 1,.flags = 0,.buf = b0,.len = 1},
-               {.addr = addr >> 1,.flags = I2C_M_RD,.buf = b1,.len = 1}
+               {.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->xfer(i2c, msgs, 2);
+       ret = i2c_transfer(state->i2c, msgs, 2);
        
        if (ret != 2)
-               dprintk("nxt6000: nxt6000_read error (.addr = 0x%02X, reg: 0x%02X, ret: %d)\n", addr, reg, ret);
+               dprintk("nxt6000: nxt6000_read error (reg: 0x%02X, ret: %d)\n", reg, ret);
        
        return b1[0];
-
 }
 
-static u8 nxt6000_readreg(struct dvb_frontend *fe, u8 reg)
+static void nxt6000_reset(struct nxt6000_state* state)
 {
-
-       struct nxt6000_config *nxt = FE2NXT(fe);
-
-       return nxt6000_read(fe->i2c, nxt->demod_addr, reg);
-}
-
-static int pll_test(struct dvb_i2c_bus *i2c, u8 demod_addr, u8 tuner_addr)
-{
-       u8 buf [1];
-       struct i2c_msg msg = {.addr = tuner_addr >> 1,.flags = I2C_M_RD,.buf = buf,.len = 1 };
-       int ret;
-
-       nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
-       ret = i2c->xfer(i2c, &msg, 1);
-       nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
-
-       return (ret != 1) ? -EFAULT : 0;
-}
-
-static int pll_write(struct dvb_i2c_bus *i2c, u8 demod_addr, u8 tuner_addr, u8 *buf, u8 len)
-{
-
-       struct i2c_msg msg = {.addr = tuner_addr >> 1, .flags = 0, .buf = buf, .len = len};
-       int ret;
-                               
-       nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01);         /* open i2c bus switch */
-       ret = i2c->xfer(i2c, &msg, 1);
-       nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00);         /* close i2c bus switch */
-                                                                               
-       if (ret != 1)
-               dprintk("nxt6000: pll_write error %d\n", ret);
-                                                                                                                               
-       return (ret != 1) ? -EFAULT : 0;
-
-}
-
-static int sp5659_set_tv_freq(struct dvb_frontend *fe, u32 freq)
-{
-
-       u8 buf[4];
-       struct nxt6000_config *nxt = FE2NXT(fe);
-
-       buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
-       buf[1] = FREQ2DIV(freq) & 0xFF;
-       buf[2] = (((FREQ2DIV(freq) >> 15) & 0x03) << 5) | 0x85;
-
-       if ((freq >= 174000000) && (freq < 230000000))
-               buf[3] = 0x82;
-       else if ((freq >= 470000000) && (freq < 782000000))
-               buf[3] = 0x85;
-       else if ((freq >= 782000000) && (freq < 863000000))
-               buf[3] = 0xC5;
-       else
-               return -EINVAL;
-
-       return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
-       
-}
-
-static int alp510_set_tv_freq(struct dvb_frontend *fe, u32 freq)
-{
-
-       u8 buf[4];
-       struct nxt6000_config *nxt = FE2NXT(fe);
-
-       buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
-       buf[1] = FREQ2DIV(freq) & 0xFF;
-       buf[2] = 0x85;
-
-#if 0
-       if ((freq >= 47000000) && (freq < 153000000))
-               buf[3] = 0x01;
-       else if ((freq >= 153000000) && (freq < 430000000))
-               buf[3] = 0x02;
-       else if ((freq >= 430000000) && (freq < 824000000))
-               buf[3] = 0x08;
-       else if ((freq >= 824000000) && (freq < 863000000))
-               buf[3] = 0x88;
-       else
-               return -EINVAL;
-#else
-       if ((freq >= 47000000) && (freq < 153000000))
-               buf[3] = 0x01;
-       else if ((freq >= 153000000) && (freq < 430000000))
-               buf[3] = 0x02;
-       else if ((freq >= 430000000) && (freq < 824000000))
-               buf[3] = 0x0C;
-       else if ((freq >= 824000000) && (freq < 863000000))
-               buf[3] = 0x8C;
-       else
-               return -EINVAL;
-#endif
-
-       return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
-       
-}
-
-static int sp5730_set_tv_freq(struct dvb_frontend *fe, u32 freq)
-{
-
-       u8 buf[4];
-       struct nxt6000_config *nxt = FE2NXT(fe);
-
-       buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
-       buf[1] = FREQ2DIV(freq) & 0xFF;
-       buf[2] = 0x93;
-
-       if ((freq >= 51000000) && (freq < 132100000))
-               buf[3] = 0x05;
-       else if ((freq >= 132100000) && (freq < 143000000))
-               buf[3] = 0x45;
-       else if ((freq >= 146000000) && (freq < 349100000))
-               buf[3] = 0x06;
-       else if ((freq >= 349100000) && (freq < 397100000))
-               buf[3] = 0x46;
-       else if ((freq >= 397100000) && (freq < 426000000))
-               buf[3] = 0x86;
-       else if ((freq >= 430000000) && (freq < 659100000))
-               buf[3] = 0x03;
-       else if ((freq >= 659100000) && (freq < 759100000))
-               buf[3] = 0x43;
-       else if ((freq >= 759100000) && (freq < 858000000))
-               buf[3] = 0x83;
-       else
-               return -EINVAL;
-
-       return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
-       
-}
-
-static void nxt6000_reset(struct dvb_frontend *fe)
-{
-
        u8 val;
 
-       val = nxt6000_readreg(fe, OFDM_COR_CTL);
-       
-       nxt6000_writereg(fe, OFDM_COR_CTL, val & ~COREACT);
-       nxt6000_writereg(fe, OFDM_COR_CTL, val | COREACT);
+       val = nxt6000_readreg(state, OFDM_COR_CTL);
        
+       nxt6000_writereg(state, OFDM_COR_CTL, val & ~COREACT);
+       nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT);
 }
 
-static int nxt6000_set_bandwidth(struct dvb_frontend *fe, fe_bandwidth_t bandwidth)
+static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth)
 {
-
        u16 nominal_rate;
        int result;
 
@@ -293,132 +114,115 @@ static int nxt6000_set_bandwidth(struct dvb_frontend *fe, fe_bandwidth_t bandwid
                        break;
 
                default:
-                       
                        return -EINVAL;
-                       
        }
 
-       if ((result = nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0)
+       if ((result = nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0)
                return result;
                
-       return nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF);
-               
+       return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF);
 }
 
-static int nxt6000_set_guard_interval(struct dvb_frontend *fe, fe_guard_interval_t guard_interval)
+static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval)
 {
-
        switch(guard_interval) {
        
                case GUARD_INTERVAL_1_32:
-
-                       return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
+               return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
 
                case GUARD_INTERVAL_1_16:
-
-                       return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
+               return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
 
                case GUARD_INTERVAL_AUTO:
                case GUARD_INTERVAL_1_8:
-
-                       return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
+               return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
 
                case GUARD_INTERVAL_1_4:
-
-                       return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
+               return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
                        
                default:
-               
                        return -EINVAL;
-
        }
-
 }
 
-static int nxt6000_set_inversion(struct dvb_frontend *fe, fe_spectral_inversion_t inversion)
+static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion)
 {
-
        switch(inversion) {
        
                case INVERSION_OFF:
-               
-                       return nxt6000_writereg(fe, OFDM_ITB_CTL, 0x00);
+               return nxt6000_writereg(state, OFDM_ITB_CTL, 0x00);
                        
                case INVERSION_ON:
-               
-                       return nxt6000_writereg(fe, OFDM_ITB_CTL, ITBINV);
+               return nxt6000_writereg(state, OFDM_ITB_CTL, ITBINV);
 
                default:
-               
                        return -EINVAL; 
        
        }
-
 }
 
-static int nxt6000_set_transmission_mode(struct dvb_frontend *fe, fe_transmit_mode_t transmission_mode)
+static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmit_mode_t transmission_mode)
 {
-
        int result;
 
        switch(transmission_mode) {
 
                case TRANSMISSION_MODE_2K:      
-
-                       if ((result = nxt6000_writereg(fe, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(fe, EN_DMD_RACQ) & ~0x03))) < 0)
+               if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
                                return result;
                                
-                       return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x04));
+               return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
 
                case TRANSMISSION_MODE_8K:      
                case TRANSMISSION_MODE_AUTO:    
-
-                       if ((result = nxt6000_writereg(fe, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(fe, EN_DMD_RACQ) & ~0x03))) < 0)
+               if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
                                return result;
 
-                       return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x04));
+               return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
 
                default:
-                       
                        return -EINVAL;
        
        }
-
 }
 
-static void nxt6000_setup(struct dvb_frontend *fe)
+static void nxt6000_setup(struct dvb_frontendfe)
 {
-
-       struct nxt6000_config *nxt = FE2NXT(fe);
-
-       nxt6000_writereg(fe, RS_COR_SYNC_PARAM, SYNC_PARAM);
-       nxt6000_writereg(fe, BER_CTRL, /*(1 << 2) |*/ (0x01 << 1) | 0x01);
-       nxt6000_writereg(fe, VIT_COR_CTL, VIT_COR_RESYNC);
-       nxt6000_writereg(fe, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(fe, OFDM_COR_CTL) & 0x0F));
-       nxt6000_writereg(fe, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02);
-       nxt6000_writereg(fe, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW);
-       nxt6000_writereg(fe, OFDM_ITB_FREQ_1, 0x06);
-       nxt6000_writereg(fe, OFDM_ITB_FREQ_2, 0x31);
-       nxt6000_writereg(fe, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04);
-       nxt6000_writereg(fe, CAS_FREQ, 0xBB);   /* CHECKME */
-       nxt6000_writereg(fe, OFDM_SYR_CTL, 1 << 2);
-       nxt6000_writereg(fe, OFDM_PPM_CTL_1, PPM256);
-       nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_1, 0x49);
-       nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_2, 0x72);
-       nxt6000_writereg(fe, ANALOG_CONTROL_0, 1 << 5);
-       nxt6000_writereg(fe, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2);
-       nxt6000_writereg(fe, DIAG_CONFIG, TB_SET);
-       
-       if (nxt->clock_inversion)
-               nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, CLKINVERSION);
+       struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
+       
+       nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM);
+       nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01);
+       nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC);
+       nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F));
+       nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02);
+       nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW);
+       nxt6000_writereg(state, OFDM_ITB_FREQ_1, 0x06);
+       nxt6000_writereg(state, OFDM_ITB_FREQ_2, 0x31);
+       nxt6000_writereg(state, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04);
+       nxt6000_writereg(state, CAS_FREQ, 0xBB);        /* CHECKME */
+       nxt6000_writereg(state, OFDM_SYR_CTL, 1 << 2);
+       nxt6000_writereg(state, OFDM_PPM_CTL_1, PPM256);
+       nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, 0x49);
+       nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, 0x72);
+       nxt6000_writereg(state, ANALOG_CONTROL_0, 1 << 5);
+       nxt6000_writereg(state, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2);
+       nxt6000_writereg(state, DIAG_CONFIG, TB_SET);
+
+       if (state->config->clock_inversion)
+               nxt6000_writereg(state, SUB_DIAG_MODE_SEL, CLKINVERSION);
        else
-               nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, 0);
-               
-       nxt6000_writereg(fe, TS_FORMAT, 0);
+               nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
 
+       nxt6000_writereg(state, TS_FORMAT, 0);
+               
+       if (state->config->pll_init) {
+               nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);        /* open i2c bus switch */
+               state->config->pll_init(fe);
+               nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);        /* close i2c bus switch */
+       }
 }
 
-static void nxt6000_dump_status(struct dvb_frontend *fe)
+static void nxt6000_dump_status(struct nxt6000_state *state)
 {
        u8 val;
 
@@ -436,12 +240,12 @@ static void nxt6000_dump_status(struct dvb_frontend *fe)
 */
        printk("NXT6000 status:");
 
-       val = nxt6000_readreg(fe, RS_COR_STAT);
+       val = nxt6000_readreg(state, RS_COR_STAT);
        
        printk(" DATA DESCR LOCK: %d,", val & 0x01);
        printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01);
 
-       val = nxt6000_readreg(fe, VIT_SYNC_STATUS);
+       val = nxt6000_readreg(state, VIT_SYNC_STATUS);
 
        printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01);
 
@@ -479,7 +283,7 @@ static void nxt6000_dump_status(struct dvb_frontend *fe)
                        
        }
 
-       val = nxt6000_readreg(fe, OFDM_COR_STAT);
+       val = nxt6000_readreg(state, OFDM_COR_STAT);
        
        printk(" CHCTrack: %d,", (val >> 7) & 0x01);
        printk(" TPSLock: %d,", (val >> 6) & 0x01);
@@ -532,7 +336,7 @@ static void nxt6000_dump_status(struct dvb_frontend *fe)
                        
        }
 
-       val = nxt6000_readreg(fe, OFDM_SYR_STAT);
+       val = nxt6000_readreg(state, OFDM_SYR_STAT);
 
        printk(" SYRLock: %d,", (val >> 4) & 0x01);
        printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K");
@@ -558,14 +362,11 @@ static void nxt6000_dump_status(struct dvb_frontend *fe)
                        break;
        
                case 0x03: 
-               
                        printk(" SYRGuard: 1/4,");
-                       
                        break;
-                       
        }
 
-       val = nxt6000_readreg(fe, OFDM_TPS_RCVD_3);
+       val = nxt6000_readreg(state, OFDM_TPS_RCVD_3);
        
        switch((val >> 4) & 0x07) {
        
@@ -635,7 +436,7 @@ static void nxt6000_dump_status(struct dvb_frontend *fe)
                        
        }
 
-       val = nxt6000_readreg(fe, OFDM_TPS_RCVD_4);
+       val = nxt6000_readreg(state, OFDM_TPS_RCVD_4);
        
        printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K");
        
@@ -668,253 +469,156 @@ static void nxt6000_dump_status(struct dvb_frontend *fe)
        }
        
        /* Strange magic required to gain access to RF_AGC_STATUS */
-       nxt6000_readreg(fe, RF_AGC_VAL_1);
-       val = nxt6000_readreg(fe, RF_AGC_STATUS);
-       val = nxt6000_readreg(fe, RF_AGC_STATUS);
+       nxt6000_readreg(state, RF_AGC_VAL_1);
+       val = nxt6000_readreg(state, RF_AGC_STATUS);
+       val = nxt6000_readreg(state, RF_AGC_STATUS);
 
        printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01);
-
        printk("\n");
-       
 }
 
-static int nxt6000_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
 
-       switch (cmd) {
 
-               case FE_GET_INFO:
 
-                       memcpy(arg, &nxt6000_info, sizeof (struct dvb_frontend_info));
 
-                       return 0;
 
-               case FE_READ_STATUS:
-               {
-                       fe_status_t *status = (fe_status_t *)arg;
 
+
+
+
+
+static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
                        u8 core_status;
+       struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
 
                        *status = 0;
                        
-                       core_status = nxt6000_readreg(fe, OFDM_COR_STAT);
+       core_status = nxt6000_readreg(state, OFDM_COR_STAT);
 
                        if (core_status & AGCLOCKED)
                                *status |= FE_HAS_SIGNAL;
 
-                       if (nxt6000_readreg(fe, OFDM_SYR_STAT) & GI14_SYR_LOCK)
+       if (nxt6000_readreg(state, OFDM_SYR_STAT) & GI14_SYR_LOCK)
                                *status |= FE_HAS_CARRIER;
 
-                       if (nxt6000_readreg(fe, VIT_SYNC_STATUS) & VITINSYNC)
+       if (nxt6000_readreg(state, VIT_SYNC_STATUS) & VITINSYNC)
                                *status |= FE_HAS_VITERBI;
 
-                       if (nxt6000_readreg(fe, RS_COR_STAT) & RSCORESTATUS)
+       if (nxt6000_readreg(state, RS_COR_STAT) & RSCORESTATUS)
                                *status |= FE_HAS_SYNC;
                                
                        if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)))
                                *status |= FE_HAS_LOCK;
                                
                        if (debug)
-                               nxt6000_dump_status(fe);
+               nxt6000_dump_status(state);
 
                        return 0;
-                       
                }
        
-               case FE_READ_BER:
+static int nxt6000_init(struct dvb_frontend* fe)
                {
-                       u32 *ber = (u32 *)arg;
+       struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
 
-                       *ber=0;
-
-                       return 0;
-                       
-               }
+       nxt6000_reset(state);
+       nxt6000_setup(fe);
        
-               case FE_READ_SIGNAL_STRENGTH:
-               {
-                       s16 *signal = (s16 *) arg;
-/*
-                       *signal=(((signed char)readreg(client, 0x16))+128)<<8;
-*/
-                       *signal = 0;
                        return 0;
-                       
-               }
-       
-               case FE_READ_SNR:
-               {
-                       s16 *snr = (s16 *) arg;
-/*
-                       *snr=readreg(client, 0x24)<<8;
-                       *snr|=readreg(client, 0x25);
-*/
-                       *snr = 0;
-                       break;
-               }
-       
-               case FE_READ_UNCORRECTED_BLOCKS: 
-               {
-                       u32 *ublocks = (u32 *)arg;
-
-                       *ublocks = 0;
-
-                       break;
                }
        
-               case FE_INIT:
-                       nxt6000_reset(fe);
-                       nxt6000_setup(fe);
-               break;
 
-               case FE_SET_FRONTEND:
+static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
                {
-                       struct nxt6000_config *nxt = FE2NXT(fe);
-                       struct dvb_frontend_parameters *param = (struct dvb_frontend_parameters *)arg;
+       struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
                        int result;
 
-                       switch(nxt->tuner_type) {
-                       
-                               case TUNER_TYPE_ALP510:
-
-                                       if ((result = alp510_set_tv_freq(fe, param->frequency)) < 0)
-                                               return result;
-                                               
-                                       break;
-
-                               case TUNER_TYPE_SP5659:
-
-                                       if ((result = sp5659_set_tv_freq(fe, param->frequency)) < 0)
-                                               return result;
-                                               
-                                       break;
-                                       
-                               case TUNER_TYPE_SP5730:
+       nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);        /* open i2c bus switch */
+       state->config->pll_set(fe, param);
+       nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);        /* close i2c bus switch */
 
-                                       if ((result = sp5730_set_tv_freq(fe, param->frequency)) < 0)
+       if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
                                                return result;
-
-                                       break;
-
-                               default:
-                               
-                                       return -EFAULT;
-                                       
-                       }
-
-                       if ((result = nxt6000_set_bandwidth(fe, param->u.ofdm.bandwidth)) < 0)
-                               return result;
-                       if ((result = nxt6000_set_guard_interval(fe, param->u.ofdm.guard_interval)) < 0)
+       if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0)
                                return result;
-                       if ((result = nxt6000_set_transmission_mode(fe, param->u.ofdm.transmission_mode)) < 0)
+       if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0)
                                return result;
-                       if ((result = nxt6000_set_inversion(fe, param->inversion)) < 0)
+       if ((result = nxt6000_set_inversion(state, param->inversion)) < 0)
                                return result;
-                       
-                       break;
-               }
-
-               default:
-
-                       return -EOPNOTSUPP;
-
-       }
 
        return 0;
-       
 } 
 
-static u8 demod_addr_tbl[] = {0x14, 0x18, 0x24, 0x28};
 
-static int nxt6000_attach(struct dvb_i2c_bus *i2c, void **data)
+static void nxt6000_release(struct dvb_frontend* fe)
 {
-       u8 addr_nr;
-       u8 fe_count = 0;
-       struct nxt6000_config *pnxt;
-
-       dprintk("nxt6000: attach\n");
-       
-       pnxt = kmalloc(sizeof(demod_addr_tbl)*sizeof(struct nxt6000_config), GFP_KERNEL);
-       if (NULL == pnxt) {
-               dprintk("nxt6000: no memory for private data.\n");
-               return -ENOMEM;
+       struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
+       kfree(state);
        }
-       *data = pnxt;
-
-       for (addr_nr = 0; addr_nr < sizeof(demod_addr_tbl); addr_nr++) {
-               struct nxt6000_config *nxt = &pnxt[addr_nr];
        
-               if (nxt6000_read(i2c, demod_addr_tbl[addr_nr], OFDM_MSC_REV) != NXT6000ASICDEVICE)
-                       continue;
-
-               if (pll_test(i2c, demod_addr_tbl[addr_nr], 0xC0) == 0) {
-                       nxt->tuner_addr = 0xC0;
-                       nxt->tuner_type = TUNER_TYPE_ALP510;
-                       nxt->clock_inversion = 1;
+static struct dvb_frontend_ops nxt6000_ops;
        
-                       dprintk("nxt6000: detected TI ALP510 tuner at 0x%02X\n", nxt->tuner_addr);
-               
-               } else if (pll_test(i2c, demod_addr_tbl[addr_nr], 0xC2) == 0) {
-                       nxt->tuner_addr = 0xC2;
-                       nxt->tuner_type = TUNER_TYPE_SP5659;
-                       nxt->clock_inversion = 0;
+struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+                                   struct i2c_adapter* i2c)
+{
+       struct nxt6000_state* state = NULL;
 
-                       dprintk("nxt6000: detected MITEL SP5659 tuner at 0x%02X\n", nxt->tuner_addr);
-               
-               } else if (pll_test(i2c, demod_addr_tbl[addr_nr], 0xC0) == 0) {
-                       nxt->tuner_addr = 0xC0;
-                       nxt->tuner_type = TUNER_TYPE_SP5730;
-                       nxt->clock_inversion = 0;
+       /* allocate memory for the internal state */
+       state = (struct nxt6000_state*) kmalloc(sizeof(struct nxt6000_state), GFP_KERNEL);
+       if (state == NULL) goto error;
 
-                       dprintk("nxt6000: detected SP5730 tuner at 0x%02X\n", nxt->tuner_addr);
-               
-               } else {
-                       printk("nxt6000: unable to detect tuner\n");
-                       continue;       
-               }
-               
-               nxt->demod_addr = demod_addr_tbl[addr_nr];
-         
-               dprintk("nxt6000: attached at %d:%d\n", i2c->adapter->num, i2c->id);
-       
-               dvb_register_frontend(nxt6000_ioctl, i2c, (void *)nxt, &nxt6000_info);
-               
-               fe_count++;
-       }
-       
-       if (fe_count == 0) {
-               kfree(pnxt);
-               return -ENODEV;
-       }
-       
-       return 0;
-}
-
-static void nxt6000_detach(struct dvb_i2c_bus *i2c, void *data)
-{
-       struct nxt6000_config *pnxt = (struct nxt6000_config *)data;
-       dprintk("nxt6000: detach\n");
-       dvb_unregister_frontend(nxt6000_ioctl, i2c);
-       kfree(pnxt);
-}
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
 
-static __init int nxt6000_init(void)
-{
+       /* check if the demod is there */
+       if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
 
-       dprintk("nxt6000: init\n");
-       
-       return dvb_register_i2c_device(THIS_MODULE, nxt6000_attach, nxt6000_detach);
-       
-}
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
 
-static __exit void nxt6000_exit(void)
-{
+error:
+       if (state) kfree(state);
+       return NULL;
+       }
 
-       dprintk("nxt6000: cleanup\n");
+static struct dvb_frontend_ops nxt6000_ops = {
+
+       .info = {
+               .name = "NxtWave NXT6000 DVB-T",
+               .type = FE_OFDM,
+               .frequency_min = 0,
+               .frequency_max = 863250000,
+               .frequency_stepsize = 62500,
+               /*.frequency_tolerance = *//* FIXME: 12% of SR */
+               .symbol_rate_min = 0,   /* FIXME */
+               .symbol_rate_max = 9360000,     /* FIXME */
+               .symbol_rate_tolerance = 4000,
+               .caps = 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_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 = nxt6000_release,
+
+       .init = nxt6000_init,
+       
+       .set_frontend = nxt6000_set_frontend,
+       
+       .read_status = nxt6000_read_status,
+};
 
-       dvb_unregister_i2c_device(nxt6000_attach);
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
-}
+MODULE_DESCRIPTION("NxtWave NXT6000 DVB-T demodulator driver");
+MODULE_AUTHOR("Florian Schirmer");
+MODULE_LICENSE("GPL");
 
-module_init(nxt6000_init);
-module_exit(nxt6000_exit);
+EXPORT_SYMBOL(nxt6000_attach);
index b47d25f..b7d9bea 100644 (file)
 /*
- * Public Include File for DRV6000 users
- * (ie. NxtWave Communications - NXT6000 demodulator driver)
- *
- * Copyright (C) 2001 NxtWave Communications, Inc.
- *
- */
+       NxtWave Communications - NXT6000 demodulator driver
 
-/*  Nxt6000 Register Addresses and Bit Masks */
+    Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
+    Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
 
-/* Maximum Register Number */
-#define MAXNXT6000REG          (0x9A)
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
 
-/* 0x1B A_VIT_BER_0  aka 0x3A */
-#define A_VIT_BER_0            (0x1B)
+    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.
 
-/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */
-#define A_VIT_BER_TIMER_0      (0x1D)
+    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.
+*/
 
-/* 0x21 RS_COR_STAT */
-#define RS_COR_STAT            (0x21)
-#define RSCORESTATUS           (0x03)
+#ifndef NXT6000_H
+#define NXT6000_H
 
-/* 0x22 RS_COR_INTEN */
-#define RS_COR_INTEN           (0x22)
+#include <linux/dvb/frontend.h>
 
-/* 0x23 RS_COR_INSTAT */
-#define RS_COR_INSTAT          (0x23)
-#define INSTAT_ERROR           (0x04)
-#define LOCK_LOSS_BITS         (0x03)
+struct nxt6000_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
 
-/* 0x24 RS_COR_SYNC_PARAM */
-#define RS_COR_SYNC_PARAM      (0x24)
-#define SYNC_PARAM             (0x03)
+       /* should clock inversion be used? */
+       u8 clock_inversion:1;
 
-/* 0x25 BER_CTRL */
-#define BER_CTRL               (0x25)
-#define BER_ENABLE             (0x02)
-#define BER_RESET              (0x01)
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
 
-/* 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)
+extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+                                          struct i2c_adapter* i2c);
 
+#endif // NXT6000_H
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
index 0aeb812..ac2c86d 100644 (file)
 /*
-   Driver for the Microtune 7202D Frontend
+   Driver for the Spase sp887x demodulator
 */
 
 /*
-   This driver needs a copy of the Avermedia firmware. The version tested
-   is part of the Avermedia DVB-T 1.3.26.3 Application. If the software is
-   installed in Windows the file will be in the /Program Files/AVerTV DVB-T/
-   directory and is called sc_main.mc. Alternatively it can "extracted" from
-   the install cab files. Copy this file to '/usr/lib/hotplug/firmware/sc_main.mc'.
-   With this version of the file the first 10 bytes are discarded and the
-   next 0x4000 loaded. This may change in future versions.
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
  */
+#define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"
 
-#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/unistd.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/i2c.h>
-#include <linux/syscalls.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
-
-#ifndef DVB_SP887X_FIRMWARE_FILE
-#define DVB_SP887X_FIRMWARE_FILE "/usr/lib/hotplug/firmware/sc_main.mc"
-#endif
-
-static char *sp887x_firmware = DVB_SP887X_FIRMWARE_FILE;
-
-#if 0
-#define dprintk(x...) printk(x)
-#else
-#define dprintk(x...)
-#endif
-
-#if 0
-#define LOG(dir,addr,buf,len)                                  \
-       do {                                                    \
-               int i;                                          \
-               printk("%s (%02x):", dir, addr & 0xff);         \
-               for (i=0; i<len; i++)                           \
-                       printk(" 0x%02x,", buf[i] & 0xff);      \
-               printk("\n");                                   \
-       } while (0)
-#else
-#define LOG(dir,addr,buf,len)
-#endif
-
-
-static
-struct dvb_frontend_info sp887x_info = {
-       .name = "Microtune MT7202DTF",
-       .type = FE_OFDM,
-       .frequency_min =  50500000,
-       .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_RECOVER
+#include "sp887x.h"
+
+
+struct sp887x_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       const struct sp887x_config* config;
+
+       struct dvb_frontend frontend;
+
+       /* demodulator private data */
+       u8 initialised:1;
 };
 
-static
-int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len)
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "sp887x: " args); \
+       } while (0)
+
+static int i2c_writebytes (struct sp887x_state* state, u8 *buf, u8 len)
 {
-       struct dvb_i2c_bus *i2c = fe->i2c;
-       struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = len };
        int err;
 
-       LOG("i2c_writebytes", msg.addr, msg.buf, msg.len);
-
-       if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+       if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
                printk ("%s: i2c write error (addr %02x, err == %i)\n",
-                       __FUNCTION__, addr, err);
+                       __FUNCTION__, state->config->demod_address, err);
                return -EREMOTEIO;
        }
 
        return 0;
 }
 
-
-
-static
-int sp887x_writereg (struct dvb_frontend *fe, u16 reg, u16 data)
+static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data)
 {
-       struct dvb_i2c_bus *i2c = fe->i2c;
        u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff };
-       struct i2c_msg msg = { .addr = 0x70, .flags = 0, .buf = b0, .len = 4 };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 4 };
        int ret;
 
-       LOG("sp887x_writereg", msg.addr, msg.buf, msg.len);
-
-       if ((ret = i2c->xfer(i2c, &msg, 1)) != 1) {
+       if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
                /**
                 *  in case of soft reset we ignore ACK errors...
                 */
-               if (!(reg == 0xf1a && data == 0x000 && 
+               if (!(reg == 0xf1a && data == 0x000 &&
                        (ret == -EREMOTEIO || ret == -EFAULT)))
                {
                        printk("%s: writereg error "
@@ -114,153 +76,103 @@ int sp887x_writereg (struct dvb_frontend *fe, u16 reg, u16 data)
        return 0;
 }
 
-
-static
-u16 sp887x_readreg (struct dvb_frontend *fe, u16 reg)
+static int sp887x_readreg (struct sp887x_state* state, u16 reg)
 {
-       struct dvb_i2c_bus *i2c = fe->i2c;
        u8 b0 [] = { reg >> 8 , reg & 0xff };
        u8 b1 [2];
        int ret;
-       struct i2c_msg msg[] = {{ .addr = 0x70, .flags = 0, .buf = b0, .len = 2 },
-                        { .addr = 0x70, .flags = I2C_M_RD, .buf = b1, .len = 2 }};
+       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 }};
 
-       LOG("sp887x_readreg (w)", msg[0].addr, msg[0].buf, msg[0].len);
-       LOG("sp887x_readreg (r)", msg[1].addr, msg[1].buf, msg[1].len);
-
-       if ((ret = i2c->xfer(i2c, msg, 2)) != 2)
+       if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
                printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+               return -1;
+       }
 
        return (((b1[0] << 8) | b1[1]) & 0xfff);
 }
 
-
-static
-void sp887x_microcontroller_stop (struct dvb_frontend *fe)
+static void sp887x_microcontroller_stop (struct sp887x_state* state)
 {
        dprintk("%s\n", __FUNCTION__);
-       sp887x_writereg(fe, 0xf08, 0x000);
-       sp887x_writereg(fe, 0xf09, 0x000);              
+       sp887x_writereg(state, 0xf08, 0x000);
+       sp887x_writereg(state, 0xf09, 0x000);
 
        /* microcontroller STOP */
-       sp887x_writereg(fe, 0xf00, 0x000);
+       sp887x_writereg(state, 0xf00, 0x000);
 }
 
-
-static
-void sp887x_microcontroller_start (struct dvb_frontend *fe)
+static void sp887x_microcontroller_start (struct sp887x_state* state)
 {
        dprintk("%s\n", __FUNCTION__);
-       sp887x_writereg(fe, 0xf08, 0x000);
-       sp887x_writereg(fe, 0xf09, 0x000);              
+       sp887x_writereg(state, 0xf08, 0x000);
+       sp887x_writereg(state, 0xf09, 0x000);
 
        /* microcontroller START */
-       sp887x_writereg(fe, 0xf00, 0x001);
+       sp887x_writereg(state, 0xf00, 0x001);
 }
 
-
-static
-void sp887x_setup_agc (struct dvb_frontend *fe)
+static void sp887x_setup_agc (struct sp887x_state* state)
 {
        /* setup AGC parameters */
        dprintk("%s\n", __FUNCTION__);
-       sp887x_writereg(fe, 0x33c, 0x054);
-       sp887x_writereg(fe, 0x33b, 0x04c);
-       sp887x_writereg(fe, 0x328, 0x000);
-       sp887x_writereg(fe, 0x327, 0x005);
-       sp887x_writereg(fe, 0x326, 0x001);
-       sp887x_writereg(fe, 0x325, 0x001);
-       sp887x_writereg(fe, 0x324, 0x001);
-       sp887x_writereg(fe, 0x318, 0x050);
-       sp887x_writereg(fe, 0x317, 0x3fe);
-       sp887x_writereg(fe, 0x316, 0x001);
-       sp887x_writereg(fe, 0x313, 0x005);
-       sp887x_writereg(fe, 0x312, 0x002);
-       sp887x_writereg(fe, 0x306, 0x000);
-       sp887x_writereg(fe, 0x303, 0x000);
+       sp887x_writereg(state, 0x33c, 0x054);
+       sp887x_writereg(state, 0x33b, 0x04c);
+       sp887x_writereg(state, 0x328, 0x000);
+       sp887x_writereg(state, 0x327, 0x005);
+       sp887x_writereg(state, 0x326, 0x001);
+       sp887x_writereg(state, 0x325, 0x001);
+       sp887x_writereg(state, 0x324, 0x001);
+       sp887x_writereg(state, 0x318, 0x050);
+       sp887x_writereg(state, 0x317, 0x3fe);
+       sp887x_writereg(state, 0x316, 0x001);
+       sp887x_writereg(state, 0x313, 0x005);
+       sp887x_writereg(state, 0x312, 0x002);
+       sp887x_writereg(state, 0x306, 0x000);
+       sp887x_writereg(state, 0x303, 0x000);
 }
 
-
 #define BLOCKSIZE 30
-
+#define FW_SIZE 0x4000
 /**
  *  load firmware and setup MPEG interface...
  */
-static
-int sp887x_initial_setup (struct dvb_frontend *fe)
+static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw)
 {
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
        u8 buf [BLOCKSIZE+2];
-       unsigned char *firmware = NULL;
        int i;
-       int fd;
-       int filesize;
-       int fw_size;
-       mm_segment_t fs;
+       int fw_size = fw->size;
+       unsigned char *mem = fw->data;
 
        dprintk("%s\n", __FUNCTION__);
 
-       /* soft reset */
-       sp887x_writereg(fe, 0xf1a, 0x000);
-
-       sp887x_microcontroller_stop (fe);
-
-       fs = get_fs();
-
-       // Load the firmware
-       set_fs(get_ds());
-       fd = sys_open(sp887x_firmware, 0, 0);
-       if (fd < 0) {
-               printk(KERN_WARNING "%s: Unable to open firmware %s\n", __FUNCTION__,
-                      sp887x_firmware);
-               return -EIO;
-       }
-       filesize = sys_lseek(fd, 0L, 2);
-       if (filesize <= 0) {
-               printk(KERN_WARNING "%s: Firmware %s is empty\n", __FUNCTION__,
-                      sp887x_firmware);
-               sys_close(fd);
-               return -EIO;
-       }
+       /* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */
+       if (fw_size < FW_SIZE+10)
+               return -ENODEV;
 
-       fw_size = 0x4000;
+       mem = fw->data + 10;
 
-       // allocate buffer for it
-       firmware = vmalloc(fw_size);
-       if (firmware == NULL) {
-               printk(KERN_WARNING "%s: Out of memory loading firmware\n",
-                      __FUNCTION__);
-               sys_close(fd);
-               return -EIO;
-       }
+       /* soft reset */
+       sp887x_writereg(state, 0xf1a, 0x000);
 
-       // read it!
-       // read the first 16384 bytes from the file
-       // ignore the first 10 bytes
-       sys_lseek(fd, 10, 0);
-       if (sys_read(fd, firmware, fw_size) != fw_size) {
-               printk(KERN_WARNING "%s: Failed to read firmware\n", __FUNCTION__);
-               vfree(firmware);
-               sys_close(fd);
-               return -EIO;
-       }
-       sys_close(fd);
-       set_fs(fs);
+       sp887x_microcontroller_stop (state);
 
        printk ("%s: firmware upload... ", __FUNCTION__);
 
        /* setup write pointer to -1 (end of memory) */
        /* bit 0x8000 in address is set to enable 13bit mode */
-       sp887x_writereg(fe, 0x8f08, 0x1fff);
+       sp887x_writereg(state, 0x8f08, 0x1fff);
 
        /* dummy write (wrap around to start of memory) */
-       sp887x_writereg(fe, 0x8f0a, 0x0000);
+       sp887x_writereg(state, 0x8f0a, 0x0000);
 
-       for (i=0; i<fw_size; i+=BLOCKSIZE) {
+       for (i = 0; i < FW_SIZE; i += BLOCKSIZE) {
                int c = BLOCKSIZE;
                int err;
 
-               if (i+c > fw_size)
-                       c = fw_size - i;
+               if (i+c > FW_SIZE)
+                       c = FW_SIZE - i;
 
                /* bit 0x8000 in address is set to enable 13bit mode */
                /* bit 0x4000 enables multibyte read/write transfers */
@@ -268,83 +180,51 @@ int sp887x_initial_setup (struct dvb_frontend *fe)
                buf[0] = 0xcf;
                buf[1] = 0x0a;
 
-               memcpy(&buf[2], firmware + i, c);
+               memcpy(&buf[2], mem + i, c);
 
-               if ((err = i2c_writebytes (fe, 0x70, buf, c+2)) < 0) {
+               if ((err = i2c_writebytes (state, buf, c+2)) < 0) {
                        printk ("failed.\n");
                        printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
-                       vfree(firmware);
                        return err;
                }
        }
 
-       vfree(firmware);
-
        /* don't write RS bytes between packets */
-       sp887x_writereg(fe, 0xc13, 0x001);
+       sp887x_writereg(state, 0xc13, 0x001);
 
        /* suppress clock if (!data_valid) */
-       sp887x_writereg(fe, 0xc14, 0x000);
+       sp887x_writereg(state, 0xc14, 0x000);
 
        /* setup MPEG interface... */
-       sp887x_writereg(fe, 0xc1a, 0x872);
-       sp887x_writereg(fe, 0xc1b, 0x001);
-       sp887x_writereg(fe, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
-       sp887x_writereg(fe, 0xc1a, 0x871);
+       sp887x_writereg(state, 0xc1a, 0x872);
+       sp887x_writereg(state, 0xc1b, 0x001);
+       sp887x_writereg(state, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
+       sp887x_writereg(state, 0xc1a, 0x871);
 
        /* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
-       sp887x_writereg(fe, 0x301, 0x002);
+       sp887x_writereg(state, 0x301, 0x002);
 
-       sp887x_setup_agc(fe);
+       sp887x_setup_agc(state);
 
        /* bit 0x010: enable data valid signal */
-       sp887x_writereg(fe, 0xd00, 0x010);
-       sp887x_writereg(fe, 0x0d1, 0x000);
+       sp887x_writereg(state, 0xd00, 0x010);
+       sp887x_writereg(state, 0x0d1, 0x000);
+
+       /* setup the PLL */
+       if (state->config->pll_init) {
+               sp887x_writereg(state, 0x206, 0x001);
+               state->config->pll_init(fe);
+               sp887x_writereg(state, 0x206, 0x000);
+       }
 
        printk ("done.\n");
        return 0;
 };
 
-
-/**
- *  returns the actual tuned center frequency which can be used
- *  to initialise the AFC registers
- */
-static
-int tsa5060_setup_pll (struct dvb_frontend *fe, int freq)
-{
-       u8 cfg, cpump, band_select;
-       u8 buf [4];
-       u32 div;
-
-       div = (36000000 + freq + 83333) / 166666;
-       cfg = 0x88;
-
-       cpump = freq < 175000000 ? 2 : freq < 390000000 ? 1 :
-               freq < 470000000 ? 2 : freq < 750000000 ? 2 : 3;
-
-       band_select = freq < 175000000 ? 0x0e : freq < 470000000 ? 0x05 : 0x03;
-
-       buf [0] = (div >> 8) & 0x7f;
-       buf [1] = div & 0xff;
-       buf [2] = ((div >> 10) & 0x60) | cfg;
-       buf [3] = cpump | band_select;
-
-       /* open i2c gate for PLL message transmission... */
-       sp887x_writereg(fe, 0x206, 0x001);
-       i2c_writebytes(fe, 0x60, buf, 4);
-       sp887x_writereg(fe, 0x206, 0x000);
-
-       return (div * 166666 - 36000000);
-}
-
-
-
-static
-int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
 {
        int known_parameters = 1;
-       
+
        *reg0xc05 = 0x000;
 
        switch (p->u.ofdm.constellation) {
@@ -412,13 +292,11 @@ int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
        return 0;
 }
 
-
 /**
  *  estimates division of two 24bit numbers,
  *  derived from the ves1820/stv0299 driver code
  */
-static
-void divide (int n, int d, int *quotient_i, int *quotient_f)
+static void divide (int n, int d, int *quotient_i, int *quotient_f)
 {
        unsigned int q, r;
 
@@ -436,9 +314,7 @@ void divide (int n, int d, int *quotient_i, int *quotient_f)
        }
 }
 
-
-static
-void sp887x_correct_offsets (struct dvb_frontend *fe,
+static void sp887x_correct_offsets (struct sp887x_state* state,
                             struct dvb_frontend_parameters *p,
                             int actual_freq)
 {
@@ -461,19 +337,31 @@ void sp887x_correct_offsets (struct dvb_frontend *fe,
                frequency_shift = -frequency_shift;
 
        /* sample rate correction */
-       sp887x_writereg(fe, 0x319, srate_correction[bw_index] >> 12);
-       sp887x_writereg(fe, 0x31a, srate_correction[bw_index] & 0xfff);
+       sp887x_writereg(state, 0x319, srate_correction[bw_index] >> 12);
+       sp887x_writereg(state, 0x31a, srate_correction[bw_index] & 0xfff);
 
        /* carrier offset correction */
-       sp887x_writereg(fe, 0x309, frequency_shift >> 12);
-       sp887x_writereg(fe, 0x30a, frequency_shift & 0xfff);
+       sp887x_writereg(state, 0x309, frequency_shift >> 12);
+       sp887x_writereg(state, 0x30a, frequency_shift & 0xfff);
 }
 
 
-static
-int sp887x_setup_frontend_parameters (struct dvb_frontend *fe,
+
+
+
+
+
+
+
+
+
+
+
+
+static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
                                      struct dvb_frontend_parameters *p)
 {
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
        int actual_freq, err;
        u16 val, reg0xc05;
 
@@ -481,18 +369,21 @@ int sp887x_setup_frontend_parameters (struct dvb_frontend *fe,
            p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ &&
            p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ)
                return -EINVAL;
-       
+
        if ((err = configure_reg0xc05(p, &reg0xc05)))
                return err;
 
-       sp887x_microcontroller_stop(fe);
+       sp887x_microcontroller_stop(state);
 
-       actual_freq = tsa5060_setup_pll(fe, p->frequency);
+       /* setup the PLL */
+       sp887x_writereg(state, 0x206, 0x001);
+       actual_freq = state->config->pll_set(fe, p);
+       sp887x_writereg(state, 0x206, 0x000);
 
-       /* read status reg in order to clear pending irqs */
-       sp887x_readreg(fe, 0x200);
+       /* read status reg in order to clear <pending irqs */
+       sp887x_readreg(state, 0x200);
 
-       sp887x_correct_offsets(fe, p, actual_freq);
+       sp887x_correct_offsets(state, p, actual_freq);
 
        /* filter for 6/7/8 Mhz channel */
        if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
@@ -502,15 +393,15 @@ int sp887x_setup_frontend_parameters (struct dvb_frontend *fe,
        else
                val = 0;
 
-       sp887x_writereg(fe, 0x311, val);
+       sp887x_writereg(state, 0x311, val);
 
        /* scan order: 2k first = 0, 8k first = 1 */
        if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
-               sp887x_writereg(fe, 0x338, 0x000);
+               sp887x_writereg(state, 0x338, 0x000);
        else
-               sp887x_writereg(fe, 0x338, 0x001);
+               sp887x_writereg(state, 0x338, 0x001);
 
-       sp887x_writereg(fe, 0xc05, reg0xc05);
+       sp887x_writereg(state, 0xc05, reg0xc05);
 
        if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
                val = 2 << 3;
@@ -522,28 +413,19 @@ int sp887x_setup_frontend_parameters (struct dvb_frontend *fe,
        /* enable OFDM and SAW bits as lock indicators in sync register 0xf17,
         * optimize algorithm for given bandwidth...
         */
-       sp887x_writereg(fe, 0xf14, 0x160 | val);
-       sp887x_writereg(fe, 0xf15, 0x000);
+       sp887x_writereg(state, 0xf14, 0x160 | val);
+       sp887x_writereg(state, 0xf15, 0x000);
 
-       sp887x_microcontroller_start(fe);
+       sp887x_microcontroller_start(state);
        return 0;
 }
 
-
-static
-int sp887x_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
-        switch (cmd) {
-        case FE_GET_INFO:
-               memcpy (arg, &sp887x_info, sizeof(struct dvb_frontend_info));
-               break;
-
-        case FE_READ_STATUS:
+static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status)
        {
-               u16 snr12 = sp887x_readreg(fe, 0xf16);
-               u16 sync0x200 = sp887x_readreg(fe, 0x200);
-               u16 sync0xf17 = sp887x_readreg(fe, 0xf17);
-               fe_status_t *status = arg;
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+       u16 snr12 = sp887x_readreg(state, 0xf16);
+       u16 sync0x200 = sp887x_readreg(state, 0x200);
+       u16 sync0xf17 = sp887x_readreg(state, 0xf17);
 
                *status = 0;
 
@@ -569,128 +451,172 @@ int sp887x_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
                               steps);
                }
 
-               break;
-
+       return 0;
        }
 
-        case FE_READ_BER:
+static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber)
        {
-               u32* ber = arg;
-               *ber = (sp887x_readreg(fe, 0xc08) & 0x3f) |
-                      (sp887x_readreg(fe, 0xc07) << 6);
-               sp887x_writereg(fe, 0xc08, 0x000);
-               sp887x_writereg(fe, 0xc07, 0x000);
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+
+       *ber = (sp887x_readreg(state, 0xc08) & 0x3f) |
+              (sp887x_readreg(state, 0xc07) << 6);
+       sp887x_writereg(state, 0xc08, 0x000);
+       sp887x_writereg(state, 0xc07, 0x000);
                if (*ber >= 0x3fff0)
                        *ber = ~0;
-               break;
 
+       return 0;
        }
 
-        case FE_READ_SIGNAL_STRENGTH:          // FIXME: correct registers ?
+static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
        {
-               u16 snr12 = sp887x_readreg(fe, 0xf16);
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+
+       u16 snr12 = sp887x_readreg(state, 0xf16);
                u32 signal = 3 * (snr12 << 4);
-               *((u16*) arg) = (signal < 0xffff) ? signal : 0xffff;
-               break;
-       }
+       *strength = (signal < 0xffff) ? signal : 0xffff;
 
-        case FE_READ_SNR:
-       {
-               u16 snr12 = sp887x_readreg(fe, 0xf16);
-               *(u16*) arg = (snr12 << 4) | (snr12 >> 8);
-               break;
+       return 0;
        }
 
-       case FE_READ_UNCORRECTED_BLOCKS:
+static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr)
        {
-               u32 *ublocks = (u32 *) arg;
-               *ublocks = sp887x_readreg(fe, 0xc0c);
-               if (*ublocks == 0xfff)
-                       *ublocks = ~0;
-               break;
-       }
-
-        case FE_SET_FRONTEND:
-               return sp887x_setup_frontend_parameters(fe, arg);
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
 
-       case FE_GET_FRONTEND:  // FIXME: read known values back from Hardware...
-               break;
+       u16 snr12 = sp887x_readreg(state, 0xf16);
+       *snr = (snr12 << 4) | (snr12 >> 8);
 
-        case FE_SLEEP:
-               /* tristate TS output and disable interface pins */
-               sp887x_writereg(fe, 0xc18, 0x000);
-               break;
-
-        case FE_INIT:
-               if (fe->data == NULL) {   /* first time initialisation... */
-                       fe->data = (void*) ~0;
-                       sp887x_initial_setup (fe);
-               }
-               /* enable TS output and interface pins */
-               sp887x_writereg(fe, 0xc18, 0x00d);
-               break;
-
-       case FE_GET_TUNE_SETTINGS:
-       {
-               struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
-               fesettings->min_delay_ms = 50;
-               fesettings->step_size = 0;
-               fesettings->max_drift = 0;
                return 0;
-       }           
+       }
 
-       default:
-               return -EOPNOTSUPP;
-        };
+static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+
+       *ucblocks = sp887x_readreg(state, 0xc0c);
+       if (*ucblocks == 0xfff)
+               *ucblocks = ~0;
 
         return 0;
 }
 
+static int sp887x_sleep(struct dvb_frontend* fe)
+{
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
 
+       /* tristate TS output and disable interface pins */
+       sp887x_writereg(state, 0xc18, 0x000);
 
-static
-int sp887x_attach (struct dvb_i2c_bus *i2c, void **data)
+       return 0;
+       }
+
+static int sp887x_init(struct dvb_frontend* fe)
 {
-       struct i2c_msg msg = {.addr = 0x70, .flags = 0, .buf = NULL, .len = 0 };
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+        const struct firmware *fw = NULL;
+       int ret;
 
-       dprintk ("%s\n", __FUNCTION__);
+       if (!state->initialised) {
+       /* request the firmware, this will block until someone uploads it */
+       printk("sp887x: waiting for firmware upload...\n");
+               ret = state->config->request_firmware(fe, &fw, SP887X_DEFAULT_FIRMWARE);
+       if (ret) {
+               printk("sp887x: no firmware upload (timeout or file not found?)\n");
+                       return ret;
+       }
 
-       if (i2c->xfer (i2c, &msg, 1) != 1)
-                return -ENODEV;
+               ret = sp887x_initial_setup(fe, fw);
+       if (ret) {
+               printk("sp887x: writing firmware to device failed\n");
+                       release_firmware(fw);
+                       return ret;
+       }
+               state->initialised = 1;
+       }
 
-       return dvb_register_frontend (sp887x_ioctl, i2c, NULL, &sp887x_info);
-}
+       /* enable TS output and interface pins */
+       sp887x_writereg(state, 0xc18, 0x00d);
 
+       return 0;
+}
 
-static
-void sp887x_detach (struct dvb_i2c_bus *i2c, void *data)
+static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
-       dprintk ("%s\n", __FUNCTION__);
-       dvb_unregister_frontend (sp887x_ioctl, i2c);
+        fesettings->min_delay_ms = 350;
+        fesettings->step_size = 166666*2;
+        fesettings->max_drift = (166666*2)+1;
+        return 0;
 }
 
-
-static
-int __init init_sp887x (void)
+static void sp887x_release(struct dvb_frontend* fe)
 {
-       dprintk ("%s\n", __FUNCTION__);
-       return dvb_register_i2c_device (NULL, sp887x_attach, sp887x_detach);
+       struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+       kfree(state);
 }
 
+static struct dvb_frontend_ops sp887x_ops;
 
-static
-void __exit exit_sp887x (void)
+struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+                                  struct i2c_adapter* i2c)
 {
-       dprintk ("%s\n", __FUNCTION__);
-       dvb_unregister_i2c_device (sp887x_attach);
-}
+       struct sp887x_state* state = NULL;
 
+       /* allocate memory for the internal state */
+       state = (struct sp887x_state*) kmalloc(sizeof(struct sp887x_state), GFP_KERNEL);
+       if (state == NULL) goto error;
 
-module_init(init_sp887x);
-module_exit(exit_sp887x);
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
+       state->initialised = 0;
 
+       /* check if the demod is there */
+       if (sp887x_readreg(state, 0x0200) < 0) goto error;
 
-MODULE_DESCRIPTION("sp887x DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
+       /* 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 sp887x_ops = {
+
+       .info = {
+               .name = "Spase SP887x DVB-T",
+               .type = FE_OFDM,
+               .frequency_min =  50500000,
+               .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_RECOVER
+       },
+
+       .release = sp887x_release,
+
+       .init = sp887x_init,
+       .sleep = sp887x_sleep,
+
+       .set_frontend = sp887x_setup_frontend_parameters,
+       .get_tune_settings = sp887x_get_tune_settings,
+
+       .read_status = sp887x_read_status,
+       .read_ber = sp887x_read_ber,
+       .read_signal_strength = sp887x_read_signal_strength,
+       .read_snr = sp887x_read_snr,
+       .read_ucblocks = sp887x_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
 
+EXPORT_SYMBOL(sp887x_attach);
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
index d01d283..3d8e780 100644 (file)
@@ -1,6 +1,5 @@
 /* 
     VES1820  - 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>
 
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <asm/div64.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
+#include "ves1820.h"
 
 
-#if 0
-#define dprintk(x...) printk(x)
-#else
-#define dprintk(x...)
-#endif
 
-#define MAX_UNITS 4
-static int pwm[MAX_UNITS] = { -1, -1, -1, -1 };
-static int verbose;
+struct ves1820_state {
+
+       struct i2c_adapter *i2c;
+
+       struct dvb_frontend_ops ops;
+
+       /* configuration settings */
+       const struct ves1820_config* config;
 
-/**
- *  since we need only a few bits to store internal state we don't allocate
- *  extra memory but use frontend->data as bitfield
- */
-
-#define SET_PWM(data,pwm) do {                 \
-       long d = (long)data;            \
-       d &= ~0xff;                     \
-       d |= pwm;                       \
-       data = (void *)d;               \
-} while (0)
-
-#define SET_REG0(data,reg0) do {       \
-       long d = (long)data;            \
-       d &= ~(0xff << 8);              \
-       d |= reg0 << 8;                 \
-       data = (void *)d;               \
-} while (0)
-
-#define SET_TUNER(data,type) do {      \
-       long d = (long)data;            \
-       d &= ~(0xff << 16);             \
-       d |= type << 16;                \
-       data = (void *)d;               \
-} while (0)
-
-#define SET_DEMOD_ADDR(data,type) do { \
-       long d = (long)data;            \
-       d &= ~(0xff << 24);             \
-       d |= type << 24;                \
-       data = (void *)d;               \
-} while (0)
-
-#define GET_PWM(data) ((u8) ((long) data & 0xff))
-#define GET_REG0(data) ((u8) (((long) data >> 8) & 0xff))
-#define GET_TUNER(data) ((u8) (((long) data >> 16) & 0xff))
-#define GET_DEMOD_ADDR(data) ((u8) (((long) data >> 24) & 0xff))
-
-#if defined(CONFIG_DBOX2)
-#define XIN 69600000UL
-#define DISABLE_INVERSION(reg0)                do { reg0 &= ~0x20; } while (0)
-#define ENABLE_INVERSION(reg0)         do { reg0 |= 0x20; } while (0)
-#define HAS_INVERSION(reg0)            (reg0 & 0x20)
-#else  /* PCI cards */
-#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))
-#endif
-
-#define FIN (XIN >> 4)
-
-
-
-static struct dvb_frontend_info ves1820_info = {
-       .name = "VES1820 based DVB-C frontend",
-       .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) */
-       .notifier_delay = ?,
-#endif
-       .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 | FE_CAN_INVERSION_AUTO,
+       struct dvb_frontend frontend;
+
+       /* private demodulator data */
+       u8 reg0;
+       u8 pwm;
 };
 
 
+static int verbose;
 
-static u8 ves1820_inittab [] =
-{
-       0x69, 0x6A, 0x9B, 0x12, 0x12, 0x46, 0x26, 0x1A,
+static u8 ves1820_inittab[] = {
+       0x69, 0x6A, 0x93, 0x12, 0x12, 0x46, 0x26, 0x1A,
        0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
        0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
@@ -127,189 +62,123 @@ static u8 ves1820_inittab [] =
        0x00, 0x00, 0x00, 0x00, 0x40
 };
 
-
-static int ves1820_writereg (struct dvb_frontend *fe, u8 reg, u8 data)
+static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
 {
-       u8 addr = GET_DEMOD_ADDR(fe->data);
         u8 buf[] = { 0x00, reg, data };
-       struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
-       struct dvb_i2c_bus *i2c = fe->i2c;
+       struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 };
         int ret;
 
-       ret = i2c->xfer (i2c, &msg, 1);
+       ret = i2c_transfer(state->i2c, &msg, 1);
 
        if (ret != 1)
-               printk("DVB: VES1820(%d): %s, writereg error "
-                       "(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-                       fe->i2c->adapter->num, __FUNCTION__, reg, data, ret);
+               printk("ves1820: %s(): writereg error (reg == 0x%02x,"
+                       "val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
 
-       dvb_delay(10);
+       msleep(10);
        return (ret != 1) ? -EREMOTEIO : 0;
 }
 
-
-static u8 ves1820_readreg (struct dvb_frontend *fe, u8 reg)
+static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
 {
        u8 b0 [] = { 0x00, reg };
        u8 b1 [] = { 0 };
-       u8 addr = GET_DEMOD_ADDR(fe->data);
-       struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b0, .len = 2 },
-                          { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-       struct dvb_i2c_bus *i2c = fe->i2c;
+       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 = 1}
+       };
        int ret;
 
-       ret = i2c->xfer (i2c, msg, 2);
+       ret = i2c_transfer(state->i2c, msg, 2);
 
        if (ret != 2)
-               printk("DVB: VES1820(%d): %s: readreg error (ret == %i)\n",
-                               fe->i2c->adapter->num, __FUNCTION__, ret);
+               printk("ves1820: %s(): readreg error (reg == 0x%02x,"
+               "ret == %i)\n", __FUNCTION__, reg, ret);
 
        return b1[0];
 }
 
 
-static int tuner_write (struct dvb_i2c_bus *i2c, u8 addr, u8 data [4])
+static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion)
 {
-        int ret;
-        struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
-
-        ret = i2c->xfer (i2c, &msg, 1);
-
-        if (ret != 1)
-                printk("DVB: VES1820(%d): %s: i/o error (ret == %i)\n",
-                               i2c->adapter->num, __FUNCTION__, ret);
-
-        return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-
-/**
- *   set up the downconverter frequency divisor for a
- *   reference clock comparision frequency of 62.5 kHz.
- */
-static int tuner_set_tv_freq (struct dvb_frontend *fe, u32 freq)
-{
-        u32 div, ifreq;
-       static u8 addr [] = { 0x61, 0x62 };
-       static u8 byte3 [] = { 0x8e, 0x85 };
-       int tuner_type = GET_TUNER(fe->data);
-        u8 buf [4];
-
-       if (tuner_type == 0xff)     /*  PLL not reachable over i2c ...  */
-               return 0;
-
-       if (strstr (fe->i2c->adapter->name, "Technotrend") ||
-           strstr (fe->i2c->adapter->name, "TT-Budget"))
-               ifreq = 35937500;
-       else
-               ifreq = 36125000;
-
-       div = (freq + ifreq + 31250) / 62500;
-
-       buf[0] = (div >> 8) & 0x7f;
-       buf[1] = div & 0xff;
-       buf[2] = byte3[tuner_type];
-
-       if (tuner_type == 1) {
-               buf[2] |= (div >> 10) & 0x60;
-               buf[3] = (freq < 174000000 ? 0x88 :
-                         freq < 470000000 ? 0x84 : 0x81);
-       } else {
-               buf[3] = (freq < 174000000 ? 0xa1 :
-                         freq < 454000000 ? 0x92 : 0x34);
-       }
-
-        return tuner_write (fe->i2c, addr[tuner_type], buf);
-}
-
-
-static int ves1820_setup_reg0 (struct dvb_frontend *fe, u8 reg0,
-                       fe_spectral_inversion_t inversion)
-{
-       reg0 |= GET_REG0(fe->data) & 0x62;
+       reg0 |= state->reg0 & 0x62;
        
-       if (INVERSION_ON == inversion)
-               ENABLE_INVERSION(reg0);
-       else if (INVERSION_OFF == inversion)
-               DISABLE_INVERSION(reg0);
+       if (INVERSION_ON == inversion) {
+               if (!state->config->invert) reg0 |= 0x20;
+               else reg0 &= ~0x20;
        
-       ves1820_writereg (fe, 0x00, reg0 & 0xfe);
-        ves1820_writereg (fe, 0x00, reg0 | 0x01);
-
-       /**
-        *  check lock and toggle inversion bit if required...
-        */
-       if (INVERSION_AUTO == inversion && !(ves1820_readreg (fe, 0x11) & 0x08)) {
-               mdelay(50);
-               if (!(ves1820_readreg (fe, 0x11) & 0x08)) {
-                       reg0 ^= 0x20;
-                       ves1820_writereg (fe, 0x00, reg0 & 0xfe);
-                       ves1820_writereg (fe, 0x00, reg0 | 0x01);
-               }
-       }
-
-       SET_REG0(fe->data, reg0);
-
-       return 0;
-}
+       } else if (INVERSION_OFF == inversion) {
 
+               if (!state->config->invert) reg0 &= ~0x20;
+               else reg0 |= 0x20;
+       }
 
-static int ves1820_init (struct dvb_frontend *fe)
-{
-       int i;
-        
-        dprintk("DVB: VES1820(%d): init chip\n", fe->i2c->adapter->num);
-
-        ves1820_writereg (fe, 0, 0);
-
-#if defined(CONFIG_DBOX2)
-       ves1820_inittab[2] &= ~0x08;
-#endif
-
-       for (i=0; i<53; i++)
-                ves1820_writereg (fe, i, ves1820_inittab[i]);
+                       ves1820_writereg(state, 0x00, reg0 & 0xfe);
+                       ves1820_writereg(state, 0x00, reg0 | 0x01);
 
-       ves1820_writereg (fe, 0x34, GET_PWM(fe->data)); 
+       state->reg0 = reg0;
 
        return 0;
 }
 
-
-static int ves1820_set_symbolrate (struct dvb_frontend *fe, u32 symbolrate)
+static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
 {
         s32 BDR; 
         s32 BDRI;
         s16 SFIL=0;
         u16 NDEC = 0;
-        u32 tmp, ratio;
+       u32 ratio;
+       u32 fin;
+       u32 tmp;
+       u64 fptmp;
+       u64 fpxin;
 
-        if (symbolrate > XIN/2) 
-                symbolrate = XIN/2;
+       if (symbolrate > state->config->xin / 2)
+               symbolrate = state->config->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;
+       if (symbolrate < state->config->xin / 16)
+               NDEC = 1;
+       if (symbolrate < state->config->xin / 32)
+               NDEC = 2;
+       if (symbolrate < state->config->xin / 64)
+               NDEC = 3;
+
+       /* yeuch! */
+       fpxin = state->config->xin * 10;
+       fptmp = fpxin; do_div(fptmp, 123);
+       if (symbolrate < fptmp);
+               SFIL = 1;
+       fptmp = fpxin; do_div(fptmp, 160);
+       if (symbolrate < fptmp);
+               SFIL = 0;
+       fptmp = fpxin; do_div(fptmp, 246);
+       if (symbolrate < fptmp);
+               SFIL = 1;
+       fptmp = fpxin; do_div(fptmp, 320);
+       if (symbolrate < fptmp);
+               SFIL = 0;
+       fptmp = fpxin; do_div(fptmp, 492);
+       if (symbolrate < fptmp);
+               SFIL = 1;
+       fptmp = fpxin; do_div(fptmp, 640);
+       if (symbolrate < fptmp);
+               SFIL = 0;
+       fptmp = fpxin; do_div(fptmp, 984);
+       if (symbolrate < fptmp);
+               SFIL = 1;
         
+       fin = state->config->xin >> 4;
         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;
+       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;
+       BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
         
         if (BDRI > 0xFF) 
                 BDRI = 0xFF;
@@ -318,21 +187,53 @@ static int ves1820_set_symbolrate (struct dvb_frontend *fe, u32 symbolrate)
         
         NDEC = (NDEC << 6) | ves1820_inittab[0x03];
 
-        ves1820_writereg (fe, 0x03, NDEC);
-        ves1820_writereg (fe, 0x0a, BDR&0xff);
-        ves1820_writereg (fe, 0x0b, (BDR>> 8)&0xff);
-        ves1820_writereg (fe, 0x0c, (BDR>>16)&0x3f);
+       ves1820_writereg(state, 0x03, NDEC);
+       ves1820_writereg(state, 0x0a, BDR & 0xff);
+       ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff);
+       ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f);
 
-        ves1820_writereg (fe, 0x0d, BDRI);
-        ves1820_writereg (fe, 0x0e, SFIL);
+       ves1820_writereg(state, 0x0d, BDRI);
+       ves1820_writereg(state, 0x0e, SFIL);
 
         return 0;
 }
 
 
-static int ves1820_set_parameters (struct dvb_frontend *fe,
-                           struct dvb_frontend_parameters *p)
+
+
+
+
+
+
+
+
+
+
+
+static int ves1820_init(struct dvb_frontend* fe)
 {
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+       int i;
+       int val;
+
+       ves1820_writereg(state, 0, 0);
+
+       for (i = 0; i < 53; i++) {
+               val = ves1820_inittab[i];
+               if ((i == 2) && (state->config->selagc)) val |= 0x08;
+               ves1820_writereg(state, i, val);
+       }
+
+       ves1820_writereg(state, 0x34, state->pwm);
+
+       if (state->config->pll_init) state->config->pll_init(fe);
+
+       return 0;
+}
+
+static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
        static const u8 reg0x00 [] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
        static const u8 reg0x01 [] = {  140,  140,  106,  100,   92 };
        static const u8 reg0x05 [] = {  135,  100,   70,   54,   38 };
@@ -343,41 +244,28 @@ static int ves1820_set_parameters (struct dvb_frontend *fe,
        if (real_qam < 0 || real_qam > 4)
                return -EINVAL;
 
-       tuner_set_tv_freq (fe, p->frequency);
-       ves1820_set_symbolrate (fe, p->u.qam.symbol_rate);
-       ves1820_writereg (fe, 0x34, GET_PWM(fe->data));
-
-        ves1820_writereg (fe, 0x01, reg0x01[real_qam]);
-        ves1820_writereg (fe, 0x05, reg0x05[real_qam]);
-        ves1820_writereg (fe, 0x08, reg0x08[real_qam]);
-        ves1820_writereg (fe, 0x09, reg0x09[real_qam]);
+       state->config->pll_set(fe, p);
+       ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
+       ves1820_writereg(state, 0x34, state->pwm);
 
-       ves1820_setup_reg0 (fe, reg0x00[real_qam], p->inversion);
+       ves1820_writereg(state, 0x01, reg0x01[real_qam]);
+       ves1820_writereg(state, 0x05, reg0x05[real_qam]);
+       ves1820_writereg(state, 0x08, reg0x08[real_qam]);
+       ves1820_writereg(state, 0x09, reg0x09[real_qam]);
 
-       /* yes, this speeds things up: userspace reports lock in about 8 ms
-          instead of 500 to 1200 ms after calling FE_SET_FRONTEND. */
-       mdelay(50);
+       ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
 
        return 0;
 }
 
-
-
-static int ves1820_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-        switch (cmd) {
-       case FE_GET_INFO:
-               memcpy (arg, &ves1820_info, sizeof(struct dvb_frontend_info));
-               break;
-
-        case FE_READ_STATUS:
-       {
-               fe_status_t *status = (fe_status_t *) arg;
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
                int sync;
 
                *status = 0;
 
-                sync = ves1820_readreg (fe, 0x11);
+                       sync = ves1820_readreg(state, 0x11);
 
                if (sync & 1)
                        *status |= FE_HAS_SIGNAL;
@@ -394,201 +282,189 @@ static int ves1820_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
                if (sync & 8)
                        *status |= FE_HAS_LOCK;
 
-               break;
+       return 0;
        }
 
-       case FE_READ_BER:
+static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber)
        {
-               u32 ber = ves1820_readreg(fe, 0x14) |
-                        (ves1820_readreg(fe, 0x15) << 8) |
-                        ((ves1820_readreg(fe, 0x16) & 0x0f) << 16);
-               *((u32*) arg) = 10 * ber;
-               break;
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+
+       u32 _ber = ves1820_readreg(state, 0x14) |
+                                       (ves1820_readreg(state, 0x15) << 8) |
+                                       ((ves1820_readreg(state, 0x16) & 0x0f) << 16);
+       *ber = 10 * _ber;
+
+       return 0;
        }
-       case FE_READ_SIGNAL_STRENGTH:
+
+static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength)
        {
-               u8 gain = ves1820_readreg(fe, 0x17);
-               *((u16*) arg) = (gain << 8) | gain;
-               break;
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+
+                       u8 gain = ves1820_readreg(state, 0x17);
+       *strength = (gain << 8) | gain;
+
+       return 0;
        }
 
-       case FE_READ_SNR:
+static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr)
        {
-               u8 quality = ~ves1820_readreg(fe, 0x18);
-               *((u16*) arg) = (quality << 8) | quality;
-               break;
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+
+                       u8 quality = ~ves1820_readreg(state, 0x18);
+       *snr = (quality << 8) | quality;
+
+       return 0;
        }
 
-       case FE_READ_UNCORRECTED_BLOCKS:
-               *((u32*) arg) = ves1820_readreg (fe, 0x13) & 0x7f;
-               if (*((u32*) arg) == 0x7f)
-                       *((u32*) arg) = 0xffffffff;
+static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+
+       *ucblocks = ves1820_readreg(state, 0x13) & 0x7f;
+       if (*ucblocks == 0x7f)
+               *ucblocks = 0xffffffff;
+
                /* reset uncorrected block counter */
-               ves1820_writereg (fe, 0x10, ves1820_inittab[0x10] & 0xdf);
-               ves1820_writereg (fe, 0x10, ves1820_inittab[0x10]);
-               break;
+               ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
+               ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
 
-        case FE_SET_FRONTEND:
-               return ves1820_set_parameters (fe, arg);
+       return 0;
+}
 
-       case FE_GET_FRONTEND:
+static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
        {
-               struct dvb_frontend_parameters *p = (struct dvb_frontend_parameters *)arg;
-               u8 reg0 = GET_REG0(fe->data);
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
                int sync;
                s8 afc = 0;
                 
-                sync = ves1820_readreg (fe, 0x11);
-                       afc = ves1820_readreg(fe, 0x19);
+                       sync = ves1820_readreg(state, 0x11);
+                       afc = ves1820_readreg(state, 0x19);
                if (verbose) {
                        /* AFC only valid when carrier has been recovered */
-                       printk(sync & 2 ? "DVB: VES1820(%d): AFC (%d) %dHz\n" :
-                                         "DVB: VES1820(%d): [AFC (%d) %dHz]\n",
-                                       fe->i2c->adapter->num, afc,
-                              -((s32)p->u.qam.symbol_rate * afc) >> 10);
+                               printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
+                                       "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
                }
 
-               p->inversion = HAS_INVERSION(reg0) ? INVERSION_ON : INVERSION_OFF;
-               p->u.qam.modulation = ((reg0 >> 2) & 7) + QAM_16;
+       if (!state->config->invert) {
+               p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF;
+       } else {
+               p->inversion = (!(state->reg0 & 0x20)) ? 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;
-               break;
-       }
-       case FE_SLEEP:
-               ves1820_writereg (fe, 0x1b, 0x02);  /* pdown ADC */
-               ves1820_writereg (fe, 0x00, 0x80);  /* standby */
-               break;
-
-        case FE_INIT:
-                return ves1820_init (fe);
-
-        default:
-                return -EINVAL;
-        }
 
         return 0;
 } 
 
-
-static long probe_tuner (struct dvb_i2c_bus *i2c)
+static int ves1820_sleep(struct dvb_frontend* fe)
 {
-       static const struct i2c_msg msg1 = 
-               { .addr = 0x61, .flags = 0, .buf = NULL, .len = 0 };
-       static const struct i2c_msg msg2 =
-               { .addr = 0x62, .flags = 0, .buf = NULL, .len = 0 };
-       int type;
-
-       if (i2c->xfer(i2c, &msg1, 1) == 1) {
-               type = 0;
-               printk ("DVB: VES1820(%d): setup for tuner spXXXX\n", i2c->adapter->num);
-       } else if (i2c->xfer(i2c, &msg2, 1) == 1) {
-               type = 1;
-               printk ("DVB: VES1820(%d): setup for tuner sp5659c\n", i2c->adapter->num);
-       } else {
-               type = -1;
-       }
-
-       return type;
-}
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
 
+       ves1820_writereg(state, 0x1b, 0x02);    /* pdown ADC */
+       ves1820_writereg(state, 0x00, 0x80);    /* standby */
 
-static u8 read_pwm (struct dvb_i2c_bus *i2c)
-{
-       u8 b = 0xff;
-       u8 pwm;
-       struct i2c_msg msg [] = { { .addr = 0x50, .flags = 0, .buf = &b, .len = 1 },
-                        { .addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1 } };
-
-       if ((i2c->xfer(i2c, msg, 2) != 2) || (pwm == 0xff))
-               pwm = 0x48;
-
-       printk("DVB: VES1820(%d): pwm=0x%02x\n", i2c->adapter->num, pwm);
-
-       return pwm;
-}
-
-
-static long probe_demod_addr (struct dvb_i2c_bus *i2c)
-{
-       u8 b [] = { 0x00, 0x1a };
-       u8 id;
-       struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b, .len = 2 },
-                          { .addr = 0x08, .flags = I2C_M_RD, .buf = &id, .len = 1 } };
-
-       if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
-               return msg[0].addr;
-
-       msg[0].addr = msg[1].addr = 0x09;
-
-       if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
-               return msg[0].addr;
-
-       return -1;
+       return 0;
 }
 
-
-static int ves1820_attach (struct dvb_i2c_bus *i2c, void **data)
+static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
-       void *priv = NULL;
-       long demod_addr;
-       long tuner_type;
 
-       if ((demod_addr = probe_demod_addr(i2c)) < 0)
-               return -ENODEV;
-
-       tuner_type = probe_tuner(i2c);
-
-       if ((i2c->adapter->num < MAX_UNITS) && pwm[i2c->adapter->num] != -1) {
-               printk("DVB: VES1820(%d): pwm=0x%02x (user specified)\n",
-                               i2c->adapter->num, pwm[i2c->adapter->num]);
-               SET_PWM(priv, pwm[i2c->adapter->num]);
-       }
-       else
-               SET_PWM(priv, read_pwm(i2c));
-       SET_REG0(priv, ves1820_inittab[0]);
-       SET_TUNER(priv, tuner_type);
-       SET_DEMOD_ADDR(priv, demod_addr);
-
-       return dvb_register_frontend (ves1820_ioctl, i2c, priv, &ves1820_info);
-}
-
-
-static void ves1820_detach (struct dvb_i2c_bus *i2c, void *data)
-{
-       dvb_unregister_frontend (ves1820_ioctl, i2c);
+       fesettings->min_delay_ms = 200;
+       fesettings->step_size = 0;
+       fesettings->max_drift = 0;
+       return 0;
 }
 
-
-static int __init init_ves1820 (void)
+static void ves1820_release(struct dvb_frontend* fe)
 {
-       int i;
-       for (i = 0; i < MAX_UNITS; i++)
-               if (pwm[i] < -1 || pwm[i] > 255)
-                       return -EINVAL;
-       return dvb_register_i2c_device (THIS_MODULE,
-                                       ves1820_attach, ves1820_detach);
+       struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+       kfree(state);
 }
 
+static struct dvb_frontend_ops ves1820_ops;
 
-static void __exit exit_ves1820 (void)
+struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+                                   struct i2c_adapter* i2c,
+                                   u8 pwm)
 {
-       dvb_unregister_i2c_device (ves1820_attach);
-}
-
+       struct ves1820_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct ves1820_state*) kmalloc(sizeof(struct ves1820_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
+       state->reg0 = ves1820_inittab[0];
+       state->config = config;
+       state->i2c = i2c;
+       state->pwm = pwm;
+
+       /* check if the demod is there */
+       if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70)
+               goto error;
+
+       if (verbose)
+               printk("ves1820: pwm=0x%02x\n", state->pwm);
+
+       state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64;      /* SACLK/64 == (XIN/2)/64 */
+       state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4;       /* SACLK/4 */
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+       }
 
-module_init(init_ves1820);
-module_exit(exit_ves1820);
+static struct dvb_frontend_ops ves1820_ops = {
+
+       .info = {
+               .name = "VLSI VES1820 DVB-C",
+               .type = FE_QAM,
+               .frequency_stepsize = 62500,
+               .frequency_min = 51000000,
+               .frequency_max = 858000000,
+               .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 = ves1820_release,
+
+       .init = ves1820_init,
+       .sleep = ves1820_sleep,
+
+       .set_frontend = ves1820_set_parameters,
+       .get_frontend = ves1820_get_frontend,
+       .get_tune_settings = ves1820_get_tune_settings,
+
+       .read_status = ves1820_read_status,
+       .read_ber = ves1820_read_ber,
+       .read_signal_strength = ves1820_read_signal_strength,
+       .read_snr = ves1820_read_snr,
+       .read_ucblocks = ves1820_read_ucblocks,
+};
 
-MODULE_PARM(pwm, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(pwm, "override PWM value stored in EEPROM (tuner calibration)");
-MODULE_PARM(verbose, "i");
+module_param(verbose, int, 0644);
 MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
 
-MODULE_DESCRIPTION("VES1820 DVB-C frontend driver");
+MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver");
 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
 MODULE_LICENSE("GPL");
 
+EXPORT_SYMBOL(ves1820_attach);
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
index 876246d..4a13dce 100644 (file)
@@ -1,5 +1,5 @@
 /* 
-    Driver for VES1893 and VES1993 QPSK Frontends
+    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>
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
+#include "ves1x93.h"
 
-static int debug = 0;
-#define dprintk        if (debug) printk
 
-static int board_type = 0;
-#define BOARD_SIEMENS_PCI      0
-#define BOARD_NOKIA_DBOX2      1
-#define BOARD_SAGEM_DBOX2      2
+struct ves1x93_state {
+
+       struct i2c_adapter* i2c;
 
-static int demod_type = 0;
-#define DEMOD_VES1893          0
-#define DEMOD_VES1993          1
+       struct dvb_frontend_ops ops;
 
-static struct dvb_frontend_info ves1x93_info = {
-       .name                   = "VES1x93",
-       .type                   = FE_QPSK,
-       .frequency_min          = 950000,
-       .frequency_max          = 2150000,
-       .frequency_stepsize     = 250,           /* kHz for QPSK frontends */
-       .frequency_tolerance    = 29500,
-       .symbol_rate_min        = 1000000,
-       .symbol_rate_max        = 45000000,
-/*      .symbol_rate_tolerance =       ???,*/
-       .notifier_delay         = 50,                /* 1/20 s */
-       .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
+       /* configuration settings */
+       const struct ves1x93_config* config;
+
+       struct dvb_frontend frontend;
+
+       /* previous uncorrected block counter */
+       fe_spectral_inversion_t inversion;
+       u8 *init_1x93_tab;
+       u8 *init_1x93_wtab;
+       u8 tab_size;
+       u8 demod_type;
 };
 
+static int debug = 0;
+#define dprintk        if (debug) printk
 
-/**
- * nokia dbox2 (ves1893) and sagem dbox2 (ves1993)
- * need bit AGCR[PWMS] set to 1
- */
+#define DEMOD_VES1893          0
+#define DEMOD_VES1993          1
 
 static u8 init_1893_tab [] = {
        0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4,
@@ -89,10 +81,6 @@ static u8 init_1993_tab [] = {
        0x00, 0x00, 0x0e, 0x80, 0x00
 };
 
-
-static u8 * init_1x93_tab;
-
-
 static u8 init_1893_wtab[] =
 {
         1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
@@ -110,19 +98,13 @@ static u8 init_1993_wtab[] =
        1,1,1,0,1,1,1,1, 1,1,1,1,1
 };
 
-struct ves1x93_state {
-       fe_spectral_inversion_t inversion;
-};
-
-
-
-static int ves1x93_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data)
 {
         u8 buf [] = { 0x00, reg, data };
-       struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 3 };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 };
        int err;
 
-        if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+       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;
        }
@@ -131,142 +113,31 @@ static int ves1x93_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
 }
 
 
-static u8 ves1x93_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg)
 {
        int ret;
        u8 b0 [] = { 0x00, reg };
        u8 b1 [] = { 0 };
-       struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b0, .len = 2 },
-                          { .addr = 0x08, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+       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 = 1 } };
 
-       ret = i2c->xfer (i2c, msg, 2);
+       ret = i2c_transfer (state->i2c, msg, 2);
 
-       if (ret != 2)
-               dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+       if (ret != 2) return ret;
 
        return b1[0];
 }
 
-
-static int tuner_write (struct dvb_i2c_bus *i2c, u8 *data, u8 len)
-{
-        int ret;
-        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = len };
-
-       ves1x93_writereg(i2c, 0x00, 0x11);
-        ret = i2c->xfer (i2c, &msg, 1);
-       ves1x93_writereg(i2c, 0x00, 0x01);
-
-        if (ret != 1)
-                printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
-
-        return (ret != 1) ? -1 : 0;
-}
-
-
-
-/**
- *   set up the downconverter frequency divisor for a
- *   reference clock comparision frequency of 125 kHz.
- */
-static int sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, u8 pwr)
-{
-        u32 div = (freq + 479500) / 125;
-       u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x95, (pwr << 5) | 0x30 };
-
-       return tuner_write (i2c, buf, sizeof(buf));
-}
-
-
-static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
-{
-       int ret;
-       u8 buf [2];
-
-       freq /= 1000;
-
-       buf[0] = (freq >> 8) & 0x7F;
-       buf[1] = freq & 0xFF;
-
-       ret = tuner_write(i2c, buf, sizeof(buf));
-
-       return ret;
-}
-
-
-static int tuner_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, u8 pwr)
-{
-       if ((demod_type == DEMOD_VES1893) && (board_type == BOARD_SIEMENS_PCI))
-               return sp5659_set_tv_freq (i2c, freq, pwr);
-       else if (demod_type == DEMOD_VES1993)
-               return tsa5059_set_tv_freq (i2c, freq);
-
-       return -EINVAL;
-}
-
-
-static int ves1x93_init (struct dvb_i2c_bus *i2c)
-{
-       int i;
-       int size;
-       u8 *init_1x93_wtab;
-       dprintk("%s: init chip\n", __FUNCTION__);
-
-       switch (demod_type) {
-       case DEMOD_VES1893:
-               init_1x93_tab = init_1893_tab;
-               init_1x93_wtab = init_1893_wtab;
-               size = sizeof(init_1893_tab);
-               if (board_type == BOARD_NOKIA_DBOX2)
-                       init_1x93_tab[0x05] |= 0x20; /* invert PWM */
-               break;
-
-       case DEMOD_VES1993:
-               init_1x93_tab = init_1993_tab;
-               init_1x93_wtab = init_1993_wtab;
-               size = sizeof(init_1993_tab);
-               if (board_type == BOARD_SAGEM_DBOX2)
-                       init_1x93_tab[0x05] |= 0x20; /* invert PWM */
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       for (i = 0; i < size; i++)
-               if (init_1x93_wtab[i])
-                       ves1x93_writereg (i2c, i, init_1x93_tab[i]);
-
-       if (demod_type == DEMOD_VES1993) {
-               if (board_type == BOARD_NOKIA_DBOX2)
-                       tuner_write(i2c, "\x06\x5c\x83\x60", 4);
-               else if (board_type == BOARD_SAGEM_DBOX2)
-                       tuner_write(i2c, "\x25\x70\x92\x40", 4);
-       }
-
-       return 0;
-}
-
-
-static int ves1x93_clr_bit (struct dvb_i2c_bus *i2c)
+static int ves1x93_clr_bit (struct ves1x93_state* state)
 {
-        ves1x93_writereg (i2c, 0, init_1x93_tab[0] & 0xfe);
-        ves1x93_writereg (i2c, 0, init_1x93_tab[0]);
-       dvb_delay(5);
+       msleep(10);
+       ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe);
+       ves1x93_writereg (state, 0, state->init_1x93_tab[0]);
+       msleep(50);
        return 0;
 }
 
-static int ves1x93_init_aquire (struct dvb_i2c_bus *i2c)
-{
-        ves1x93_writereg (i2c, 3, 0x00);
-       ves1x93_writereg (i2c, 3, init_1x93_tab[3]);
-       dvb_delay(5);
-       return 0;
-}
-
-
-static int ves1x93_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion_t inversion)
+static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion)
 {
        u8 val;
 
@@ -289,66 +160,47 @@ static int ves1x93_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion
                return -EINVAL;
        }
 
-       return ves1x93_writereg (i2c, 0x0c, (init_1x93_tab[0x0c] & 0x3f) | val);
+       return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val);
 }
 
 
-static int ves1x93_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
+static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec)
 {
        if (fec == FEC_AUTO)
-               return ves1x93_writereg (i2c, 0x0d, 0x08);
+               return ves1x93_writereg (state, 0x0d, 0x08);
        else if (fec < FEC_1_2 || fec > FEC_8_9)
                return -EINVAL;
        else
-               return ves1x93_writereg (i2c, 0x0d, fec - FEC_1_2);
+               return ves1x93_writereg (state, 0x0d, fec - FEC_1_2);
 }
 
 
-static fe_code_rate_t ves1x93_get_fec (struct dvb_i2c_bus *i2c)
+static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state)
 {
-       return FEC_1_2 + ((ves1x93_readreg (i2c, 0x0d) >> 4) & 0x7);
+       return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7);
 }
 
 
-static int ves1x93_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
+static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
 {
        u32 BDR;
         u32 ratio;
        u8  ADCONF, FCONF, FNR;
        u32 BDRI;
        u32 tmp;
-       u32 XIN, FIN;
+       u32 FIN;
 
        dprintk("%s: srate == %d\n", __FUNCTION__, (unsigned int) srate);
 
-       switch (board_type) {
-       case BOARD_SIEMENS_PCI:
-               XIN = 90100000UL;
-               break;
-       case BOARD_NOKIA_DBOX2:
-               if (demod_type == DEMOD_VES1893)
-                       XIN = 91000000UL;
-               else if (demod_type == DEMOD_VES1993)
-                       XIN = 96000000UL;
-               else
-                       return -EINVAL;
-               break;
-       case BOARD_SAGEM_DBOX2:
-               XIN = 92160000UL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (srate > XIN/2)
-               srate = XIN/2;
+       if (srate > state->config->xin/2)
+               srate = state->config->xin/2;
 
        if (srate < 500000)
                srate = 500000;
 
 #define MUL (1UL<<26)
 
-       FIN = (XIN + 6000) >> 4;
+       FIN = (state->config->xin + 6000) >> 4;
 
        tmp = srate << 6;
        ratio = tmp / FIN;
@@ -393,75 +245,102 @@ static int ves1x93_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
        if (BDRI > 0xff)
                BDRI = 0xff;
 
-       ves1x93_writereg (i2c, 0x06, 0xff & BDR);
-       ves1x93_writereg (i2c, 0x07, 0xff & (BDR >> 8));
-       ves1x93_writereg (i2c, 0x08, 0x0f & (BDR >> 16));
+       ves1x93_writereg (state, 0x06, 0xff & BDR);
+       ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8));
+       ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16));
 
-       ves1x93_writereg (i2c, 0x09, BDRI);
-       ves1x93_writereg (i2c, 0x20, ADCONF);
-       ves1x93_writereg (i2c, 0x21, FCONF);
+       ves1x93_writereg (state, 0x09, BDRI);
+       ves1x93_writereg (state, 0x20, ADCONF);
+       ves1x93_writereg (state, 0x21, FCONF);
 
        if (srate < 6000000) 
-               ves1x93_writereg (i2c, 0x05, init_1x93_tab[0x05] | 0x80);
+               ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] | 0x80);
        else
-               ves1x93_writereg (i2c, 0x05, init_1x93_tab[0x05] & 0x7f);
+               ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] & 0x7f);
 
        /* ves1993 hates this, will lose lock */
-       if (demod_type != DEMOD_VES1993)
-               ves1x93_clr_bit (i2c);
+       if (state->demod_type != DEMOD_VES1993)
+               ves1x93_clr_bit (state);
 
        return 0;
 }
 
 
-static int ves1x93_afc (struct dvb_i2c_bus *i2c, u32 freq, u32 srate)
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int ves1x93_init (struct dvb_frontend* fe)
 {
-       int afc;
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+       int i;
+       int val;
 
-       afc = ((int)((ves1x93_readreg (i2c, 0x0a) << 1) & 0xff))/2;
-       afc = (afc * (int)(srate/1000/8))/16;
-    
-       if (afc) {
-       
-               freq -= afc;
+       dprintk("%s: init chip\n", __FUNCTION__);
 
-               tuner_set_tv_freq (i2c, freq, 0);
+       for (i = 0; i < state->tab_size; i++) {
+               if (state->init_1x93_wtab[i]) {
+                       val = state->init_1x93_tab[i];
+
+                       if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */
+                       ves1x93_writereg (state, i, val);
+               }
+       }
 
-               ves1x93_init_aquire (i2c);
+       if (state->config->pll_init) {
+               ves1x93_writereg(state, 0x00, 0x11);
+               state->config->pll_init(fe);
+               ves1x93_writereg(state, 0x00, 0x01);
        }
-       
+
        return 0;
 }
 
-static int ves1x93_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
+static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+
        switch (voltage) {
        case SEC_VOLTAGE_13:
-               return ves1x93_writereg (i2c, 0x1f, 0x20);
+               return ves1x93_writereg (state, 0x1f, 0x20);
        case SEC_VOLTAGE_18:
-               return ves1x93_writereg (i2c, 0x1f, 0x30);
+               return ves1x93_writereg (state, 0x1f, 0x30);
        case SEC_VOLTAGE_OFF:
-               return ves1x93_writereg (i2c, 0x1f, 0x00);
+               return ves1x93_writereg (state, 0x1f, 0x00);
        default:
                return -EINVAL;
        }
 }
 
-
-static int ves1x93_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-       struct dvb_i2c_bus *i2c = fe->i2c;
-       struct ves1x93_state *state = (struct ves1x93_state*) fe->data;
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
 
-        switch (cmd) {
-        case FE_GET_INFO:
-               memcpy (arg, &ves1x93_info, sizeof(struct dvb_frontend_info));
-               break;
+       u8 sync = ves1x93_readreg (state, 0x0e);
 
-        case FE_READ_STATUS:
-       {
-               fe_status_t *status = arg;
-               u8 sync = ves1x93_readreg (i2c, 0x0e);
+               /*
+                * The ves1893 sometimes returns sync values that make no sense,
+                * because, e.g., the SIGNAL bit is 0, while some of the higher
+                * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
+                * Tests showed that the the VITERBI and SYNC bits are returned
+                * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
+                * If such a case occurs, we read the value again, until we get a
+                * valid value.
+                */
+               int maxtry = 10; /* just for safety - let's not get stuck here */
+               while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
+                       msleep(10);
+               sync = ves1x93_readreg (state, 0x0e);
+               }
 
                *status = 0;
 
@@ -480,65 +359,78 @@ static int ves1x93_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
                if ((sync & 0x1f) == 0x1f)
                        *status |= FE_HAS_LOCK;
 
-               break;
+       return 0;
        }
 
-        case FE_READ_BER:
+
+static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber)
        {
-               u32 *ber = (u32 *) arg;
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
 
-               *ber = ves1x93_readreg (i2c, 0x15);
-                *ber |= (ves1x93_readreg (i2c, 0x16) << 8);
-                *ber |= ((ves1x93_readreg (i2c, 0x17) & 0x0F) << 16);
+       *ber = ves1x93_readreg (state, 0x15);
+       *ber |= (ves1x93_readreg (state, 0x16) << 8);
+       *ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16);
                *ber *= 10;
-               break;
+
+       return 0;
        }
 
-        case FE_READ_SIGNAL_STRENGTH:
+static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength)
        {
-               u8 signal = ~ves1x93_readreg (i2c, 0x0b);
-               *((u16*) arg) = (signal << 8) | signal;
-               break;
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+
+       u8 signal = ~ves1x93_readreg (state, 0x0b);
+       *strength = (signal << 8) | signal;
+
+       return 0;
        }
 
-        case FE_READ_SNR:
+static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr)
        {
-               u8 snr = ~ves1x93_readreg (i2c, 0x1c);
-               *(u16*) arg = (snr << 8) | snr;
-               break;
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+
+       u8 _snr = ~ves1x93_readreg (state, 0x1c);
+       *snr = (_snr << 8) | _snr;
+
+       return 0;
        }
 
-       case FE_READ_UNCORRECTED_BLOCKS: 
+static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        {
-               *(u32*) arg = ves1x93_readreg (i2c, 0x18) & 0x7f;
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
 
-               if (*(u32*) arg == 0x7f)
-                       *(u32*) arg = 0xffffffff;   /* counter overflow... */
+       *ucblocks = ves1x93_readreg (state, 0x18) & 0x7f;
                
-               ves1x93_writereg (i2c, 0x18, 0x00);  /* reset the counter */
-               ves1x93_writereg (i2c, 0x18, 0x80);  /* dto. */
-               break;
+       if (*ucblocks == 0x7f)
+               *ucblocks = 0xffffffff;   /* counter overflow... */
+
+       ves1x93_writereg (state, 0x18, 0x00);  /* reset the counter */
+       ves1x93_writereg (state, 0x18, 0x80);  /* dto. */
+
+       return 0;
        }
 
-        case FE_SET_FRONTEND:
+static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
         {
-               struct dvb_frontend_parameters *p = arg;
-
-               tuner_set_tv_freq (i2c, p->frequency, 0);
-               ves1x93_set_inversion (i2c, p->inversion);
-               ves1x93_set_fec (i2c, p->u.qpsk.fec_inner);
-               ves1x93_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
-               ves1x93_afc (i2c, p->frequency, p->u.qpsk.symbol_rate);     
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+
+       ves1x93_writereg(state, 0x00, 0x11);
+       state->config->pll_set(fe, p);
+       ves1x93_writereg(state, 0x00, 0x01);
+       ves1x93_set_inversion (state, p->inversion);
+       ves1x93_set_fec (state, p->u.qpsk.fec_inner);
+       ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
                state->inversion = p->inversion;
-                break;
+
+       return 0;
         }
 
-       case FE_GET_FRONTEND:
+static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
        {
-               struct dvb_frontend_parameters *p = arg;
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
                int afc;
 
-               afc = ((int)((char)(ves1x93_readreg (i2c, 0x0a) << 1)))/2;
+       afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
                afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;
 
                p->frequency -= afc;
@@ -548,113 +440,125 @@ static int ves1x93_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
                 * if auto inversion was used
                 */
                if (state->inversion == INVERSION_AUTO)
-                       p->inversion = (ves1x93_readreg (i2c, 0x0f) & 2) ? 
+               p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
                                        INVERSION_OFF : INVERSION_ON;
-               p->u.qpsk.fec_inner = ves1x93_get_fec (i2c);
+       p->u.qpsk.fec_inner = ves1x93_get_fec (state);
        /*  XXX FIXME: timing offset !! */
-               break;
-       }
-
-        case FE_SLEEP:
-               if (board_type == BOARD_SIEMENS_PCI)
-                       ves1x93_writereg (i2c, 0x1f, 0x00);    /*  LNB power off  */
-               return ves1x93_writereg (i2c, 0x00, 0x08);
-
-        case FE_INIT:
-               return ves1x93_init (i2c);
 
-       case FE_SET_TONE:
-               return -EOPNOTSUPP;  /* the ves1893 can generate the 22k */
-                                    /* let's implement this when we have */
-                                    /* a box that uses the 22K_0 pin... */
+       return 0;
+}
 
-       case FE_SET_VOLTAGE:
-               return ves1x93_set_voltage (i2c, (fe_sec_voltage_t) arg);
+static int ves1x93_sleep(struct dvb_frontend* fe)
+{
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
 
-       default:
-               return -EOPNOTSUPP;
-        };
+       return ves1x93_writereg (state, 0x00, 0x08);
+}
         
-        return 0;
+static void ves1x93_release(struct dvb_frontend* fe)
+{
+       struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+       kfree(state);
 } 
 
+static struct dvb_frontend_ops ves1x93_ops;
 
-static int ves1x93_attach (struct dvb_i2c_bus *i2c, void **data)
+struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+                                   struct i2c_adapter* i2c)
 {
-       u8 identity = ves1x93_readreg(i2c, 0x1e);
-       struct ves1x93_state* state;
+       struct ves1x93_state* state = NULL;
+       u8 identity;
+
+       /* allocate memory for the internal state */
+       state = (struct ves1x93_state*) kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
+       state->inversion = INVERSION_OFF;
 
+       /* check if the demod is there + identify it */
+       identity = ves1x93_readreg(state, 0x1e);
        switch (identity) {
        case 0xdc: /* VES1893A rev1 */
                printk("ves1x93: Detected ves1893a rev1\n");
-               demod_type = DEMOD_VES1893;
-               ves1x93_info.name[4] = '8';
+               state->demod_type = DEMOD_VES1893;
+               state->init_1x93_tab = init_1893_tab;
+               state->init_1x93_wtab = init_1893_wtab;
+               state->tab_size = sizeof(init_1893_tab);
                break;
+
        case 0xdd: /* VES1893A rev2 */
                printk("ves1x93: Detected ves1893a rev2\n");
-               demod_type = DEMOD_VES1893;
-               ves1x93_info.name[4] = '8';
+               state->demod_type = DEMOD_VES1893;
+               state->init_1x93_tab = init_1893_tab;
+               state->init_1x93_wtab = init_1893_wtab;
+               state->tab_size = sizeof(init_1893_tab);
                break;
+
        case 0xde: /* VES1993 */
                printk("ves1x93: Detected ves1993\n");
-               demod_type = DEMOD_VES1993;
-               ves1x93_info.name[4] = '9';
+               state->demod_type = DEMOD_VES1993;
+               state->init_1x93_tab = init_1993_tab;
+               state->init_1x93_wtab = init_1993_wtab;
+               state->tab_size = sizeof(init_1993_tab);
                break;
-       default:
-               dprintk("VES1x93 not found (identity %02x)\n", identity);
-               return -ENODEV;
-       }
 
-       if ((state = kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL)) == NULL) {
-               return -ENOMEM;
-       }
-       state->inversion = INVERSION_OFF;
-       *data = state;
-
-       return dvb_register_frontend (ves1x93_ioctl, i2c, (void*) state, &ves1x93_info);
-}
-
-
-static void ves1x93_detach (struct dvb_i2c_bus *i2c, void *data)
-{
-       kfree(data);
-       dvb_unregister_frontend (ves1x93_ioctl, i2c);
-}
-
-
-static int __init init_ves1x93 (void)
-{
-       switch (board_type) {
-       case BOARD_NOKIA_DBOX2:
-               dprintk("%s: NOKIA_DBOX2\n", __FILE__);
-               break;
-       case BOARD_SAGEM_DBOX2:
-               dprintk("%s: SAGEM_DBOX2\n", __FILE__);
-               break;
-       case BOARD_SIEMENS_PCI:
-               dprintk("%s: SIEMENS_PCI\n", __FILE__);
-               break;
        default:
-               return -EIO;
+               goto error;
        }
 
-       return dvb_register_i2c_device (THIS_MODULE, ves1x93_attach, ves1x93_detach);
-}
-
-
-static void __exit exit_ves1x93 (void)
-{
-       dvb_unregister_i2c_device (ves1x93_attach);
-}
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
 
+error:
+       if (state) kfree(state);
+       return NULL;
+       }
 
-module_init(init_ves1x93);
-module_exit(exit_ves1x93);
+static struct dvb_frontend_ops ves1x93_ops = {
+
+       .info = {
+               .name                   = "VLSI VES1x93 DVB-S",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 125,           /* kHz for QPSK frontends */
+               .frequency_tolerance    = 29500,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+       /*      .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_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK
+       },
+
+       .release = ves1x93_release,
+
+       .init = ves1x93_init,
+       .sleep = ves1x93_sleep,
+
+       .set_frontend = ves1x93_set_frontend,
+       .get_frontend = ves1x93_get_frontend,
+
+       .read_status = ves1x93_read_status,
+       .read_ber = ves1x93_read_ber,
+       .read_signal_strength = ves1x93_read_signal_strength,
+       .read_snr = ves1x93_read_snr,
+       .read_ucblocks = ves1x93_read_ucblocks,
+
+       .set_voltage = ves1x93_set_voltage,
+};
 
+module_param(debug, int, 0644);
 
-MODULE_DESCRIPTION("VES1x93 DVB-S Frontend");
+MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver");
 MODULE_AUTHOR("Ralph Metzler");
 MODULE_LICENSE("GPL");
-MODULE_PARM(debug,"i");
-MODULE_PARM(board_type,"i");
 
+EXPORT_SYMBOL(ves1x93_attach);
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
index a5ff5ec..edb9c73 100644 (file)
@@ -4,6 +4,12 @@ config DVB_AV7110
        select FW_LOADER
        select VIDEO_DEV
        select VIDEO_SAA7146_VV
+       select DVB_VES1820
+       select DVB_VES1X93
+       select DVB_STV0299
+       select DVB_TDA8083
+       select DVB_SP8870
+       select DVB_STV0297
        help
          Support for SAA7146 and AV7110 based DVB cards as produced 
          by Fujitsu-Siemens, Technotrend, Hauppauge and others.
@@ -11,11 +17,16 @@ config DVB_AV7110
          This driver only supports the fullfeatured cards with
          onboard MPEG2 decoder.
 
+          This driver needs an external firmware. Please use the script
+          "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
+          download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+
          Say Y if you own such a card and want to use it.
 
 config DVB_AV7110_FIRMWARE
        bool "Compile AV7110 firmware into the driver"
        depends on DVB_AV7110 && !STANDALONE
+       default y if DVB_AV7110=y
        help
          The AV7110 firmware is normally loaded by the firmware hotplug manager.
          If you want to compile the firmware into the driver you need to say
@@ -33,6 +44,7 @@ config DVB_AV7110_FIRMWARE_FILE
 config DVB_AV7110_OSD
        bool "AV7110 OSD support"
        depends on DVB_AV7110
+       default y if DVB_AV7110=y || DVB_AV7110=m
        help
          The AV7110 firmware provides some code to generate an OnScreenDisplay
          on the video output. This is kind of nonstandard and not guaranteed to
@@ -47,6 +59,12 @@ config DVB_BUDGET
        tristate "Budget cards"
        depends on DVB_CORE && PCI
        select VIDEO_SAA7146
+       select DVB_STV0299
+       select DVB_VES1X93
+       select DVB_VES1820
+       select DVB_L64781
+       select DVB_TDA8083
+       select DVB_TDA10021
        help
          Support for simple SAA7146 based DVB cards
          (so called Budget- or Nova-PCI cards) without onboard
@@ -61,6 +79,8 @@ config DVB_BUDGET_CI
        tristate "Budget cards with onboard CI connector"
        depends on DVB_CORE && PCI
        select VIDEO_SAA7146
+       select DVB_STV0299
+       select DVB_TDA1004X
        help
          Support for simple SAA7146 based DVB cards
          (so called Budget- or Nova-PCI cards) without onboard
@@ -79,6 +99,7 @@ config DVB_BUDGET_AV
        depends on DVB_CORE && PCI
        select VIDEO_DEV
        select VIDEO_SAA7146_VV
+       select DVB_STV0299
        help
          Support for simple SAA7146 based DVB cards
          (so called Budget- or Nova-PCI cards) without onboard
@@ -91,8 +112,11 @@ config DVB_BUDGET_AV
 
 config DVB_BUDGET_PATCH
        tristate "AV7110 cards with Budget Patch"
-       depends on DVB_BUDGET
+       depends on DVB_CORE && DVB_BUDGET
        select DVB_AV7110
+       select DVB_STV0299
+       select DVB_VES1X93
+       select DVB_TDA8083
        help
          Support for Budget Patch (full TS) modification on 
          SAA7146+AV7110 based cards (DVB-S cards). This
index 043468a..825ab1c 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
 obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
 obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 
 hostprogs-y    := fdump
 
index c9485ee..f25a825 100644 (file)
@@ -4,13 +4,12 @@
 #include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/netdevice.h>
+#include <linux/i2c.h>
 
 #ifdef CONFIG_DEVFS_FS
 #include <linux/devfs_fs_kernel.h>
 #endif
 
-#include <media/saa7146_vv.h>
-
 #include <linux/dvb/video.h>
 #include <linux/dvb/audio.h>
 #include <linux/dvb/dmx.h>
 #include "dvb_filter.h"
 #include "dvb_net.h"
 #include "dvb_ringbuffer.h"
+#include "dvb_frontend.h"
+#include "ves1820.h"
+#include "ves1x93.h"
+#include "stv0299.h"
+#include "tda8083.h"
+#include "sp8870.h"
+#include "stv0297.h"
+
+#include <media/saa7146_vv.h>
+
 
+#define ANALOG_TUNER_VES1820 1
+#define ANALOG_TUNER_STV0297 2
+#define ANALOG_TUNER_VBI     0x100
+
+extern int av7110_debug;
+
+#define dprintk(level,args...) \
+           do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __FUNCTION__); printk(args); } } while (0)
 
 #define MAXFILT 32
 
@@ -60,16 +77,17 @@ struct av7110 {
         struct dvb_device       dvb_dev;
         struct dvb_net               dvb_net;
 
-       struct video_device     v4l_dev;
-       struct video_device     vbi_dev;
+       struct video_device     *v4l_dev;
+       struct video_device     *vbi_dev;
 
         struct saa7146_dev     *dev;
 
-       struct dvb_i2c_bus      *i2c_bus;       
+       struct i2c_adapter      i2c_adap;
+
        char                    *card_name;
 
        /* support for analog module of dvb-c */
-       int                     has_analog_tuner;
+       int                     analog_tuner_flags;
        int                     current_input;
        u32                     current_freq;
                                
@@ -109,8 +127,8 @@ struct av7110 {
 
         spinlock_t              debilock;
         struct semaphore        dcomlock;
-        int                     debitype;
-        int                     debilen;
+       volatile int            debitype;
+       volatile int            debilen;
 
 
         /* Recording and playback flags */
@@ -127,7 +145,7 @@ struct av7110 {
 
         int                     osdwin;      /* currently active window */
         u16                     osdbpp[8];
-
+       struct semaphore        osd_sema;
 
         /* CA */
 
@@ -187,6 +205,7 @@ struct av7110 {
         struct dvb_ringbuffer    ci_rbuffer;
         struct dvb_ringbuffer    ci_wbuffer;
 
+       struct audio_mixer      mixer;
 
         struct dvb_adapter       *dvb_adapter;
         struct dvb_device        *video_dev;
@@ -210,6 +229,18 @@ struct av7110 {
 
        unsigned char *bin_root;
        unsigned long size_root;
+
+       struct dvb_frontend* fe;
+       fe_status_t fe_status;
+       int (*fe_init)(struct dvb_frontend* fe);
+       int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
+       int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
+       int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+       int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+       int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+       int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+       int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+       int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 
index 826ea87..bf901c6 100644 (file)
@@ -39,29 +39,6 @@ enum av7110_osd_palette_type
        Pal8Bit =  256     /* 256 colors for 16 bit palette */
 };
 
-enum av7110_window_display_type {
-       BITMAP1,           /* 1 bit bitmap */
-       BITMAP2,           /* 2 bit bitmap */
-       BITMAP4,           /* 4 bit bitmap */
-       BITMAP8,           /* 8 bit bitmap */
-       BITMAP1HR,         /* 1 Bit bitmap half resolution */
-       BITMAP2HR,         /* 2 bit bitmap half resolution */
-       BITMAP4HR,         /* 4 bit bitmap half resolution */
-       BITMAP8HR,         /* 8 bit bitmap half resolution */
-       YCRCB422,          /* 4:2:2 YCRCB Graphic Display */
-       YCRCB444,          /* 4:4:4 YCRCB Graphic Display */
-       YCRCB444HR,        /* 4:4:4 YCRCB graphic half resolution */
-       VIDEOTSIZE,        /* True Size Normal MPEG Video Display */
-       VIDEOHSIZE,        /* MPEG Video Display Half Resolution */
-       VIDEOQSIZE,        /* MPEG Video Display Quarter Resolution */
-       VIDEODSIZE,        /* MPEG Video Display Double Resolution */
-       VIDEOTHSIZE,       /* True Size MPEG Video Display Half Resolution */
-       VIDEOTQSIZE,       /* True Size MPEG Video Display Quarter Resolution*/
-       VIDEOTDSIZE,       /* True Size MPEG Video Display Double Resolution */
-       VIDEONSIZE,        /* Full Size MPEG Video Display */
-       CURSOR             /* Cursor */
-};
-
 /* switch defines */
 #define SB_GPIO 3
 #define SB_OFF SAA7146_GPIO_OUTLO  /* SlowBlank off (TV-Mode) */
@@ -88,6 +65,9 @@ enum av7110_video_output_mode
 #define HPQOver                0x0008
 #define OSDQFull       0x0010          /* OSD Queue Full */
 #define OSDQOver       0x0020
+#define GPMQBusy       0x0040          /* Queue not empty, FW >= 261d */
+#define HPQBusy                0x0080
+#define OSDQBusy       0x0100
 
 /* hw section filter flags */
 #define        SECTION_EIT             0x01
@@ -388,8 +368,10 @@ extern void av7110_reset_arm(struct av7110 *av7110);
 extern int av7110_bootarm(struct av7110 *av7110);
 extern int av7110_firmversion(struct av7110 *av7110);
 #define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000)
+#define FW_4M_SDRAM(arm_app)      ((arm_app) & 0x40000000)
 #define FW_VERSION(arm_app)      ((arm_app) & 0x0000FFFF)
 
+extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags);
 extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...);
 extern int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length);
 extern int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length);
@@ -495,7 +477,7 @@ static int inline vidcom(struct av7110 *av7110, u32 com, u32 arg)
 
 static int inline audcom(struct av7110 *av7110, u32 com)
 {
-       return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 4,
+       return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2,
                             (com>>16), (com&0xffff));
 }
 
@@ -510,6 +492,7 @@ extern int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned
 
 #ifdef CONFIG_DVB_AV7110_OSD
 extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc);
+extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap);
 #endif /* CONFIG_DVB_AV7110_OSD */
 
 
index fef348e..822ccda 100644 (file)
 #include <linux/byteorder/swabb.h>
 #include <linux/smp_lock.h>
 
-#define DEBUG_VARIABLE av7110_debug
-extern int av7110_debug;
-
-#include "dvb_i2c.h"
 #include "av7110.h"
 #include "av7110_hw.h"
 #include "av7110_av.h"
-#include "dvb_functions.h"
-
 
 int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
 {
        u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
-       struct dvb_i2c_bus *i2c = av7110->i2c_bus;
        struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg };
 
-       if (i2c->xfer(i2c, &msgs, 1) != 1) {
-               printk("av7110(%d): %s(%u = %u) failed\n",
-                      av7110->dvb_adapter->num, __FUNCTION__, reg, val);
+       if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
+               dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
+                      av7110->dvb_adapter->num, reg, val);
                return -EIO;
        }
        return 0;
@@ -63,15 +56,14 @@ int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
 {
        u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
        u8 msg2[2];
-       struct dvb_i2c_bus *i2c = av7110->i2c_bus;
        struct i2c_msg msgs[2] = {
                { .flags = 0,        .addr = 0x40, .len = 3, .buf = msg1 },
                { .flags = I2C_M_RD, .addr = 0x40, .len = 2, .buf = msg2 }
        };
 
-       if (i2c->xfer(i2c, msgs, 2) != 2) {
-               printk("av7110(%d): %s(%u) failed\n",
-                      av7110->dvb_adapter->num, __FUNCTION__, reg);
+       if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
+               dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
+                      av7110->dvb_adapter->num, reg);
                return -EIO;
        }
        *val = (msg2[0] << 8) | msg2[1];
@@ -100,43 +92,47 @@ static struct v4l2_input inputs[2] = {
        }
 };
 
-/* for Siemens DVB-C analog module: (taken from ves1820.c) */
-static int ves1820_writereg(struct saa7146_dev *dev, u8 reg, u8 data)
+static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
 {
-       u8 addr = 0x09;
        u8 buf[] = { 0x00, reg, data };
        struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
 
-       DEB_EE(("av7710: dev: %p\n", dev));
+       dprintk(4, "dev: %p\n", dev);
+
+       if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
+               return -1;
+       return 0;
+}
+
+static int stv0297_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
+{
+        u8 buf [] = { reg, data };
+        struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 2 };
 
        if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
                return -1;
        return 0;
 }
 
+
 static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
 {
        struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
 
-       DEB_EE(("av7710: dev: %p\n", dev));
+       dprintk(4, "dev: %p\n", dev);
 
        if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
                return -1;
        return 0;
 }
 
-
-/**
- *   set up the downconverter frequency divisor for a
- *   reference clock comparision frequency of 62.5 kHz.
- */
-static int tuner_set_tv_freq(struct saa7146_dev *dev, u32 freq)
+static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
 {
        u32 div;
        u8 config;
        u8 buf[4];
 
-       DEB_EE(("av7710: freq: 0x%08x\n", freq));
+       dprintk(4, "freq: 0x%08x\n", freq);
 
        /* magic number: 614. tuning with the frequency given by v4l2
           is always off by 614*62.5 = 38375 kHz...*/
@@ -159,6 +155,34 @@ static int tuner_set_tv_freq(struct saa7146_dev *dev, u32 freq)
        return tuner_write(dev, 0x61, buf);
 }
 
+static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
+{
+       u32 div;
+       u8 data[4];
+
+       div = (freq + 38900000 + 31250) / 62500;
+
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = 0xce;
+
+       if (freq < 45000000)
+               return -EINVAL;
+       else if (freq < 137000000)
+               data[3] = 0x01;
+       else if (freq < 403000000)
+               data[3] = 0x02;
+       else if (freq < 860000000)
+               data[3] = 0x04;
+       else
+               return -EINVAL;
+
+       stv0297_writereg(dev, 0x1C, 0x87, 0x78);
+       stv0297_writereg(dev, 0x1C, 0x86, 0xc8);
+       return tuner_write(dev, 0x63, data);
+}
+
+
 
 static struct saa7146_standard analog_standard[];
 static struct saa7146_standard dvb_standard[];
@@ -170,60 +194,71 @@ static struct v4l2_audio msp3400_v4l2_audio = {
        .capability = V4L2_AUDCAP_STEREO
 };
 
-int av7110_dvb_c_switch(struct saa7146_fh *fh)
+static int av7110_dvb_c_switch(struct saa7146_fh *fh)
 {
        struct saa7146_dev *dev = fh->dev;
        struct saa7146_vv *vv = dev->vv_data;
        struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
        u16 adswitch;
-       u8 band = 0;
        int source, sync, err;
 
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
 
        if ((vv->video_status & STATUS_OVERLAY) != 0) {
                vv->ov_suspend = vv->video_fh;
                err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
                if (err != 0) {
-                       DEB_D(("warning: suspending video failed\n"));
+                       dprintk(2, "suspending video failed\n");
                        vv->ov_suspend = NULL;
                }
        }
 
        if (0 != av7110->current_input) {
                adswitch = 1;
-               band = 0x60; /* analog band */
                source = SAA7146_HPS_SOURCE_PORT_B;
                sync = SAA7146_HPS_SYNC_PORT_B;
                memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2);
-               printk("av7110: switching to analog TV\n");
+               dprintk(1, "switching to analog TV\n");
                msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source
                msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source
                msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source
                msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
                msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
                msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
+
+               if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
+                       if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
+                               dprintk(1, "setting band in demodulator failed.\n");
+               } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
+                       saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD)
+                       saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9198 pin30(VIF)
+               }
        } else {
                adswitch = 0;
-               band = 0x20; /* digital band */
                source = SAA7146_HPS_SOURCE_PORT_A;
                sync = SAA7146_HPS_SYNC_PORT_A;
                memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
-               printk("av7110: switching DVB mode\n");
+               dprintk(1, "switching DVB mode\n");
                msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
                msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
                msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
                msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
                msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
                msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
+
+               if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
+                       if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
+                               dprintk(1, "setting band in demodulator failed.\n");
+               } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
+                       saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD)
+                       saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
+               }
        }
 
        /* hmm, this does not do anything!? */
        if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch))
-               printk("ADSwitch error\n");
+               dprintk(1, "ADSwitch error\n");
 
-       if (ves1820_writereg(dev, 0x0f, band))
-               printk("setting band in demodulator failed.\n");
        saa7146_set_hps_source_and_sync(dev, source, sync);
 
        if (vv->ov_suspend != NULL) {
@@ -234,11 +269,11 @@ int av7110_dvb_c_switch(struct saa7146_fh *fh)
        return 0;
 }
 
-int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
        struct saa7146_dev *dev = fh->dev;
        struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
-       DEB_EE(("saa7146_dev: %p\n", dev));
+       dprintk(4, "saa7146_dev: %p\n", dev);
 
        switch (cmd) {
        case VIDIOC_G_TUNER:
@@ -247,9 +282,9 @@ int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                u16 stereo_det;
                s8 stereo;
 
-               DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
+               dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
 
-               if (!av7110->has_analog_tuner || t->index != 0)
+               if (!av7110->analog_tuner_flags || t->index != 0)
                        return -EINVAL;
 
                memset(t, 0, sizeof(*t));
@@ -266,10 +301,10 @@ int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 
                // FIXME: standard / stereo detection is still broken
                msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
-printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
+               dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
 
                msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
-               printk("VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
+               dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
                stereo = (s8)(stereo_det >> 8);
                if (stereo > 0x10) {
                        /* stereo */
@@ -290,29 +325,29 @@ printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
        {
                struct v4l2_tuner *t = arg;
                u16 fm_matrix, src;
-               DEB_EE(("VIDIOC_S_TUNER: %d\n", t->index));
+               dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
 
-               if (!av7110->has_analog_tuner || av7110->current_input != 1)
+               if (!av7110->analog_tuner_flags || av7110->current_input != 1)
                        return -EINVAL;
 
                switch (t->audmode) {
                case V4L2_TUNER_MODE_STEREO:
-                       DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
+                       dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
                        fm_matrix = 0x3001; // stereo
                        src = 0x0020;
                        break;
                case V4L2_TUNER_MODE_LANG1:
-                       DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
+                       dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
                        fm_matrix = 0x3000; // mono
                        src = 0x0000;
                        break;
                case V4L2_TUNER_MODE_LANG2:
-                       DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
+                       dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
                        fm_matrix = 0x3000; // mono
                        src = 0x0010;
                        break;
                default: /* case V4L2_TUNER_MODE_MONO: {*/
-                       DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
+                       dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
                        fm_matrix = 0x3000; // mono
                        src = 0x0030;
                        break;
@@ -327,9 +362,9 @@ printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
        {
                struct v4l2_frequency *f = arg;
 
-               DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency));
+               dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
 
-               if (!av7110->has_analog_tuner || av7110->current_input != 1)
+               if (!av7110->analog_tuner_flags || av7110->current_input != 1)
                        return -EINVAL;
 
                memset(f, 0, sizeof(*f));
@@ -341,9 +376,9 @@ printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
        {
                struct v4l2_frequency *f = arg;
 
-               DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency));
+               dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
 
-               if (!av7110->has_analog_tuner || av7110->current_input != 1)
+               if (!av7110->analog_tuner_flags || av7110->current_input != 1)
                        return -EINVAL;
 
                if (V4L2_TUNER_ANALOG_TV != f->type)
@@ -353,7 +388,11 @@ printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
                msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
 
                /* tune in desired frequency */
-               tuner_set_tv_freq(dev, f->frequency);
+               if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
+                       ves1820_set_tv_freq(dev, f->frequency);
+               } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
+                       stv0297_set_tv_freq(dev, f->frequency);
+               }
                av7110->current_freq = f->frequency;
 
                msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); // start stereo detection
@@ -366,9 +405,9 @@ printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
        {
                struct v4l2_input *i = arg;
 
-               DEB_EE(("VIDIOC_ENUMINPUT: %d\n", i->index));
+               dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
 
-               if (av7110->has_analog_tuner ) {
+               if (av7110->analog_tuner_flags) {
                        if (i->index < 0 || i->index >= 2)
                                return -EINVAL;
                } else {
@@ -384,16 +423,16 @@ printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
        {
                int *input = (int *)arg;
                *input = av7110->current_input;
-               DEB_EE(("VIDIOC_G_INPUT: %d\n", *input));
+               dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
                return 0;
        }
        case VIDIOC_S_INPUT:
        {
                int input = *(int *)arg;
 
-               DEB_EE(("VIDIOC_S_INPUT: %d\n", input));
+               dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
 
-               if (!av7110->has_analog_tuner )
+               if (!av7110->analog_tuner_flags)
                        return 0;
 
                if (input < 0 || input >= 2)
@@ -407,7 +446,7 @@ printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
        {
                struct v4l2_audio *a = arg;
 
-               DEB_EE(("VIDIOC_G_AUDIO: %d\n", a->index));
+               dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
                if (a->index != 0)
                        return -EINVAL;
                memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
@@ -416,7 +455,7 @@ printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
        case VIDIOC_S_AUDIO:
        {
                struct v4l2_audio *a = arg;
-               DEB_EE(("VIDIOC_S_AUDIO: %d\n", a->index));
+               dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
                break;
        }
        default:
@@ -431,7 +470,7 @@ printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
  * INITIALIZATION
  ****************************************************************************/
 
-struct saa7146_extension_ioctls ioctls[] = {
+static struct saa7146_extension_ioctls ioctls[] = {
        { VIDIOC_ENUMINPUT,     SAA7146_EXCLUSIVE },
        { VIDIOC_G_INPUT,       SAA7146_EXCLUSIVE },
        { VIDIOC_S_INPUT,       SAA7146_EXCLUSIVE },
@@ -514,13 +553,13 @@ int av7110_init_analog_module(struct av7110 *av7110)
            || i2c_writereg(av7110, 0x80, 0x0, 0) != 1)
                return -ENODEV;
 
-       printk("av7110(%d): DVB-C analog module detected, initializing MSP3400\n",
+       printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
                av7110->dvb_adapter->num);
        av7110->adac_type = DVB_ADAC_MSP;
-       dvb_delay(100); // the probing above resets the msp...
+       msleep(100); // the probing above resets the msp...
        msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
        msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
-       printk("av7110(%d): MSP3400 version 0x%04x 0x%04x\n",
+       dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n",
                av7110->dvb_adapter->num, version1, version2);
        msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
        msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
@@ -535,12 +574,31 @@ int av7110_init_analog_module(struct av7110 *av7110)
                INFO(("saa7113 not accessible.\n"));
        } else {
                u8 *i = saa7113_init_regs;
-               av7110->has_analog_tuner = 1;
+
+               if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
+                       /* Fujitsu/Siemens DVB-Cable */
+                       av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
+               } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) {
+                       /* Hauppauge/TT DVB-C premium */
+                       av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
+               } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) {
+                       /* Hauppauge/TT DVB-C premium */
+                       av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297;
+               }
+
+               /* setup for DVB by default */
+               if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
+                       if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
+                               dprintk(1, "setting band in demodulator failed.\n");
+               } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
+                       saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD)
+                       saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
+               }
+
                /* init the saa7113 */
                while (*i != 0xff) {
                        if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) {
-                               printk("av7110(%d): saa7113 initialization failed",
-                                               av7110->dvb_adapter->num);
+                               dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter->num);
                                break;
                        }
                        i += 2;
@@ -587,7 +645,7 @@ int av7110_init_v4l(struct av7110 *av7110)
        /* special case DVB-C: these cards have an analog tuner
           plus need some special handling, so we have separate
           saa7146_ext_vv data for these... */
-       if (av7110->has_analog_tuner)
+       if (av7110->analog_tuner_flags)
                ret = saa7146_vv_init(dev, &av7110_vv_data_c);
        else
                ret = saa7146_vv_init(dev, &av7110_vv_data_st);
@@ -602,12 +660,12 @@ int av7110_init_v4l(struct av7110 *av7110)
                saa7146_vv_release(dev);
                return -ENODEV;
        }
-       if (av7110->has_analog_tuner) {
+       if (av7110->analog_tuner_flags) {
                if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
                        ERR(("cannot register vbi v4l2 device. skipping.\n"));
-               } else
-                       /* we use this to remember that this dvb-c card can do vbi */
-                       av7110->has_analog_tuner = 2;
+               } else {
+                       av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
+               }
        }
        return 0;
 }
@@ -615,7 +673,7 @@ int av7110_init_v4l(struct av7110 *av7110)
 int av7110_exit_v4l(struct av7110 *av7110)
 {
        saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
-       if (2 == av7110->has_analog_tuner)
+       if (av7110->analog_tuner_flags & ANALOG_TUNER_VBI)
                saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
        return 0;
 }
@@ -692,7 +750,7 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
        .flags          = 0,
 
        .stds           = &standard[0],
-       .num_stds       = sizeof(standard) / sizeof(struct saa7146_standard),
+       .num_stds       = ARRAY_SIZE(standard),
        .std_callback   = &std_callback,
 
        .ioctls         = &ioctls[0],
@@ -706,7 +764,7 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
        .flags          = SAA7146_USE_PORT_B_FOR_VBI,
 
        .stds           = &standard[0],
-       .num_stds       = sizeof(standard) / sizeof(struct saa7146_standard),
+       .num_stds       = ARRAY_SIZE(standard),
        .std_callback   = &std_callback,
 
        .ioctls         = &ioctls[0],
index 6203be4..ae92600 100644 (file)
@@ -4,6 +4,9 @@
  *
  * Compiled from various sources by Michael Hunold <michael@mihu.de> 
  *
+ * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
+ *                               Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
  * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
  *
  * Copyright (C) 1999-2002 Ralph  Metzler 
  * the project's page is at http://www.linuxtv.org/dvb/
  */
 
+#include "budget.h"
+#include "stv0299.h"
+#include "tda10021.h"
+#include "tda1004x.h"
 #include <media/saa7146_vv.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/spinlock.h>
 
-#include "budget.h"
-#include "dvb_functions.h"
+#include "dvb_ca_en50221.h"
+
+#define DEBICICAM              0x02420000
 
 struct budget_av {
        struct budget budget;
-       struct video_device vd;
+       struct video_device *vd;
        int cur_input;
        int has_saa7113;
+       struct tasklet_struct ciintf_irq_tasklet;
+       int slot_status;
+       struct dvb_ca_en50221 ca;
 };
 
+int enable_ci = 0;
+
+
 /****************************************************************************
  * INITIALIZATION
  ****************************************************************************/
 
 
-static u8 i2c_readreg (struct dvb_i2c_bus *i2c, u8 id, u8 reg)
+static u8 i2c_readreg (struct i2c_adapter *i2c, u8 id, u8 reg)
 {
        u8 mm1[] = {0x00};
        u8 mm2[] = {0x00};
@@ -57,15 +77,17 @@ static u8 i2c_readreg (struct dvb_i2c_bus *i2c, u8 id, u8 reg)
        msgs[1].flags = I2C_M_RD;
        msgs[0].addr = msgs[1].addr=id/2;
        mm1[0] = reg;
-       msgs[0].len = 1; msgs[1].len = 1;
-       msgs[0].buf = mm1; msgs[1].buf = mm2;
+       msgs[0].len = 1;
+       msgs[1].len = 1;
+       msgs[0].buf = mm1;
+       msgs[1].buf = mm2;
 
-       i2c->xfer(i2c, msgs, 2);
+       i2c_transfer(i2c, msgs, 2);
 
        return mm2[0];
 }
 
-static int i2c_readregs(struct dvb_i2c_bus *i2c, u8 id, u8 reg, u8 *buf, u8 len)
+static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 *buf, u8 len)
 {
         u8 mm1[] = { reg };
         struct i2c_msg msgs[2] = {
@@ -73,13 +95,14 @@ static int i2c_readregs(struct dvb_i2c_bus *i2c, u8 id, u8 reg, u8 *buf, u8 len)
                { .addr = id/2, .flags = I2C_M_RD, .buf = buf, .len = len }
        };
 
-        if (i2c->xfer(i2c, msgs, 2) != 2)
+        if (i2c_transfer(i2c, msgs, 2) != 2)
                return -EIO;
+
        return 0;
 }
 
 
-static int i2c_writereg (struct dvb_i2c_bus *i2c, u8 id, u8 reg, u8 val)
+static int i2c_writereg (struct i2c_adapter *i2c, u8 id, u8 reg, u8 val)
 {
         u8 msg[2]={ reg, val }; 
         struct i2c_msg msgs;
@@ -88,7 +111,212 @@ static int i2c_writereg (struct dvb_i2c_bus *i2c, u8 id, u8 reg, u8 val)
         msgs.addr=id/2;
         msgs.len=2;
         msgs.buf=msg;
-        return i2c->xfer (i2c, &msgs, 1);
+        return i2c_transfer(i2c, &msgs, 1);
+}
+
+static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
+{
+       struct budget_av *budget_av = (struct budget_av *) ca->data;
+       int result;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+       result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0);
+
+       if (result == -ETIMEDOUT)
+               budget_av->slot_status = 0;
+       return result;
+}
+
+static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
+{
+       struct budget_av *budget_av = (struct budget_av *) ca->data;
+       int result;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+       result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0);
+
+       if (result == -ETIMEDOUT)
+               budget_av->slot_status = 0;
+       return result;
+}
+
+static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
+{
+       struct budget_av *budget_av = (struct budget_av *) ca->data;
+       int result;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+       result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
+
+       if (result == -ETIMEDOUT)
+               budget_av->slot_status = 0;
+       return result;
+}
+
+static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
+{
+       struct budget_av *budget_av = (struct budget_av *) ca->data;
+       int result;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+       result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
+
+       if (result == -ETIMEDOUT)
+               budget_av->slot_status = 0;
+       return result;
+}
+
+static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct budget_av *budget_av = (struct budget_av *) ca->data;
+       struct saa7146_dev *saa = budget_av->budget.dev;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       dprintk(1, "ciintf_slot_reset\n");
+
+       /* reset the card */
+       saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
+       msleep(100);
+       saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+       msleep(2000);           /* horrendous I know, but its the only way to be absolutely sure without an IRQ line! */
+
+       ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+       return 0;
+}
+
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct budget_av *budget_av = (struct budget_av *) ca->data;
+       struct saa7146_dev *saa = budget_av->budget.dev;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       dprintk(1, "ciintf_slot_shutdown\n");
+
+       ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+       budget_av->slot_status = 0;
+       return 0;
+}
+
+static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct budget_av *budget_av = (struct budget_av *) ca->data;
+       struct saa7146_dev *saa = budget_av->budget.dev;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
+
+       ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+       return 0;
+}
+
+static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+       struct budget_av *budget_av = (struct budget_av *) ca->data;
+       struct saa7146_dev *saa = budget_av->budget.dev;
+       int cam = 0;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       if (!budget_av->slot_status) {
+               saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
+               udelay(1);
+               cam = saa7146_read(saa, PSR) & MASK_06;
+               saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+
+               if (cam)
+                       budget_av->slot_status = 1;
+       } else if (!open) {
+               saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+               if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
+                       budget_av->slot_status = 0;
+       }
+
+       if (budget_av->slot_status == 1)
+               return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+
+       return 0;
+}
+
+static int ciintf_init(struct budget_av *budget_av)
+{
+       struct saa7146_dev *saa = budget_av->budget.dev;
+       int result;
+
+       memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221));
+
+       /* setup GPIOs */
+       saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
+       saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO);
+       saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+
+       /* Reset the card */
+       saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
+       msleep(50);
+       saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+       msleep(100);
+
+       /* Enable DEBI pins */
+       saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
+
+       /* register CI interface */
+       budget_av->ca.owner = THIS_MODULE;
+       budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem;
+       budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem;
+       budget_av->ca.read_cam_control = ciintf_read_cam_control;
+       budget_av->ca.write_cam_control = ciintf_write_cam_control;
+       budget_av->ca.slot_reset = ciintf_slot_reset;
+       budget_av->ca.slot_shutdown = ciintf_slot_shutdown;
+       budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
+       budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
+       budget_av->ca.data = budget_av;
+       if ((result = dvb_ca_en50221_init(budget_av->budget.dvb_adapter,
+                                         &budget_av->ca, 0, 1)) != 0) {
+               printk("budget_av: CI interface detected, but initialisation failed.\n");
+               goto error;
+       }
+       // success!
+       printk("ciintf_init: CI interface initialised\n");
+       budget_av->budget.ci_present = 1;
+       return 0;
+
+error:
+       saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+       return result;
+}
+
+static void ciintf_deinit(struct budget_av *budget_av)
+{
+       struct saa7146_dev *saa = budget_av->budget.dev;
+
+       saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
+       saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
+       saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
+       saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
+
+       /* release the CA device */
+       dvb_ca_en50221_release(&budget_av->ca);
+
+       /* disable DEBI pins */
+       saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
 }
 
 
@@ -127,20 +355,19 @@ static int saa7113_init (struct budget_av *budget_av)
        struct budget *budget = &budget_av->budget;
        const u8 *data = saa7113_tab;
 
-        if (i2c_writereg (budget->i2c_bus, 0x4a, 0x01, 0x08) != 1) {
-                DEB_D(("saa7113: not found on KNC card\n"));
+        if (i2c_writereg (&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) {
+                dprintk(1, "saa7113 not found on KNC card\n");
                 return -ENODEV;
         }
 
-        INFO(("saa7113: detected and initializing\n"));
+        dprintk(1, "saa7113 detected and initializing\n");
 
        while (*data != 0xff) {
-                i2c_writereg(budget->i2c_bus, 0x4a, *data, *(data+1));
+                i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data+1));
                 data += 2;
         }
 
-       DEB_D(("saa7113: status=%02x\n",
-             i2c_readreg(budget->i2c_bus, 0x4a, 0x1f)));
+       dprintk(1, "saa7113  status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f));
 
        return 0;
 }
@@ -154,11 +381,11 @@ static int saa7113_setinput (struct budget_av *budget_av, int input)
                return -ENODEV;
 
        if (input == 1) {
-               i2c_writereg(budget->i2c_bus, 0x4a, 0x02, 0xc7);
-               i2c_writereg(budget->i2c_bus, 0x4a, 0x09, 0x80);
+               i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7);
+               i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80);
        } else if (input == 0) {
-               i2c_writereg(budget->i2c_bus, 0x4a, 0x02, 0xc0);
-               i2c_writereg(budget->i2c_bus, 0x4a, 0x09, 0x00);
+               i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0);
+               i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00);
        } else
                return -EINVAL;
 
@@ -167,21 +394,405 @@ static int saa7113_setinput (struct budget_av *budget_av, int input)
 }
 
 
+static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+       u8 aclk = 0;
+       u8 bclk = 0;
+       u8 m1;
+
+       aclk = 0xb5;
+       if (srate < 2000000)
+               bclk = 0x86;
+       else if (srate < 5000000)
+               bclk = 0x89;
+       else if (srate < 15000000)
+               bclk = 0x8f;
+       else if (srate < 45000000)
+               bclk = 0x95;
+
+       m1 = 0x14;
+       if (srate < 4000000)
+               m1 = 0x10;
+
+       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);
+       stv0299_writereg(fe, 0x0f, 0x80 | m1);
+
+       return 0;
+}
+
+static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
+                                       struct dvb_frontend_parameters *params)
+{
+       struct budget_av *budget_av = (struct budget_av *) fe->dvb->priv;
+       u32 div;
+       u8 buf[4];
+       struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+       if ((params->frequency < 950000) || (params->frequency > 2150000))
+               return -EINVAL;
+
+       div = (params->frequency + (125 - 1)) / 125;    // round correctly
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+       buf[3] = 0x20;
+
+       if (params->u.qpsk.symbol_rate < 4000000)
+               buf[3] |= 1;
+
+       if (params->frequency < 1250000)
+               buf[3] |= 0;
+       else if (params->frequency < 1550000)
+               buf[3] |= 0x40;
+       else if (params->frequency < 2050000)
+               buf[3] |= 0x80;
+       else if (params->frequency < 2150000)
+               buf[3] |= 0xC0;
+
+       if (i2c_transfer(&budget_av->budget.i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static u8 typhoon_cinergy1200s_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x30,
+       0x03, 0x00,
+       0x04, 0x7d,             /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+       0x05, 0x35,             /* I2CT = 0, SCLT = 1, SDAT = 1 */
+       0x06, 0x40,             /* DAC not used, set to high impendance mode */
+       0x07, 0x00,             /* DAC LSB */
+       0x08, 0x40,             /* DiSEqC off */
+       0x09, 0x00,             /* FIFO */
+       0x0c, 0x51,             /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+       0x0d, 0x82,             /* DC offset compensation = ON, beta_agc1 = 2 */
+       0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
+       0x10, 0x3f,             // AGC2  0x3d
+       0x11, 0x84,
+       0x12, 0xb5,             // Lock detect: -64  Carrier freq detect:on
+       0x15, 0xc9,             // lock detector threshold
+       0x16, 0x00,
+       0x17, 0x00,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1a, 0x00,
+       0x1f, 0x50,
+       0x20, 0x00,
+       0x21, 0x00,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x28, 0x00,             // out imp: normal  out type: parallel FEC mode:0
+       0x29, 0x1e,             // 1/2 threshold
+       0x2a, 0x14,             // 2/3 threshold
+       0x2b, 0x0f,             // 3/4 threshold
+       0x2c, 0x09,             // 5/6 threshold
+       0x2d, 0x05,             // 7/8 threshold
+       0x2e, 0x01,
+       0x31, 0x1f,             // test all FECs
+       0x32, 0x19,             // viterbi and synchro search
+       0x33, 0xfc,             // rs control
+       0x34, 0x93,             // error control
+       0x0f, 0x92,
+       0xff, 0xff
+};
+
+static struct stv0299_config typhoon_config = {
+       .demod_address = 0x68,
+       .inittab = typhoon_cinergy1200s_inittab,
+       .mclk = 88000000UL,
+       .invert = 0,
+       .enhanced_tuning = 0,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP0,
+       .min_delay_ms = 100,
+       .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+       .pll_set = philips_su1278_ty_ci_pll_set,
+};
+
+
+static struct stv0299_config cinergy_1200s_config = {
+       .demod_address = 0x68,
+       .inittab = typhoon_cinergy1200s_inittab,
+       .mclk = 88000000UL,
+       .invert = 0,
+       .enhanced_tuning = 0,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_0,
+       .volt13_op0_op1 = STV0299_VOLT13_OP0,
+       .min_delay_ms = 100,
+       .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+       .pll_set = philips_su1278_ty_ci_pll_set,
+};
+
+
+static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       struct budget *budget = (struct budget *) fe->dvb->priv;
+       u8 buf[4];
+       struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+#define TUNER_MUL 62500
+
+       u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = 0x8e;
+       buf[3] = (params->frequency < 174500000 ? 0xa1 :
+                 params->frequency < 454000000 ? 0x92 : 0x34);
+
+       if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static struct tda10021_config philips_cu1216_config = {
+       .demod_address = 0x0c,
+       .pll_set = philips_cu1216_pll_set,
+};
+
+
+
+
+static int philips_tu1216_pll_init(struct dvb_frontend *fe)
+{
+       struct budget *budget = (struct budget *) fe->dvb->priv;
+       static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+       struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+       // setup PLL configuration
+       if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
+               return -EIO;
+       msleep(1);
+
+       return 0;
+}
+
+static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       struct budget *budget = (struct budget *) fe->dvb->priv;
+       u8 tuner_buf[4];
+       struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
+                       sizeof(tuner_buf) };
+       int tuner_frequency = 0;
+       u8 band, cp, filter;
+
+       // determine charge pump
+       tuner_frequency = params->frequency + 36166000;
+       if (tuner_frequency < 87000000)
+               return -EINVAL;
+       else if (tuner_frequency < 130000000)
+               cp = 3;
+       else if (tuner_frequency < 160000000)
+               cp = 5;
+       else if (tuner_frequency < 200000000)
+               cp = 6;
+       else if (tuner_frequency < 290000000)
+               cp = 3;
+       else if (tuner_frequency < 420000000)
+               cp = 5;
+       else if (tuner_frequency < 480000000)
+               cp = 6;
+       else if (tuner_frequency < 620000000)
+               cp = 3;
+       else if (tuner_frequency < 830000000)
+               cp = 5;
+       else if (tuner_frequency < 895000000)
+               cp = 7;
+       else
+               return -EINVAL;
+
+       // determine band
+       if (params->frequency < 49000000)
+               return -EINVAL;
+       else if (params->frequency < 161000000)
+               band = 1;
+       else if (params->frequency < 444000000)
+               band = 2;
+       else if (params->frequency < 861000000)
+               band = 4;
+       else
+               return -EINVAL;
+
+       // setup PLL filter
+       switch (params->u.ofdm.bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               filter = 0;
+               break;
+
+       case BANDWIDTH_7_MHZ:
+               filter = 0;
+               break;
+
+       case BANDWIDTH_8_MHZ:
+               filter = 1;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       // calculate divisor
+       // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
+       tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;
+
+       // setup tuner buffer
+       tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
+       tuner_buf[1] = tuner_frequency & 0xff;
+       tuner_buf[2] = 0xca;
+       tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+       if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
+               return -EIO;
+
+       msleep(1);
+       return 0;
+}
+
+static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
+                                          const struct firmware **fw, char *name)
+{
+       struct budget *budget = (struct budget *) fe->dvb->priv;
+
+       return request_firmware(fw, name, &budget->dev->pci->dev);
+}
+
+struct tda1004x_config philips_tu1216_config = {
+
+       .demod_address = 0x8,
+       .invert = 1,
+       .invert_oclk = 1,
+       .pll_init = philips_tu1216_pll_init,
+       .pll_set = philips_tu1216_pll_set,
+       .request_firmware = philips_tu1216_request_firmware,
+};
+
+
+
+
+static u8 read_pwm(struct budget_av *budget_av)
+{
+       u8 b = 0xff;
+       u8 pwm;
+       struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1},
+       {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
+       };
+
+       if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2)
+           || (pwm == 0xff))
+               pwm = 0x48;
+
+       return pwm;
+}
+
+
+static void frontend_init(struct budget_av *budget_av)
+{
+       switch (budget_av->budget.dev->pci->subsystem_device) {
+       case 0x4f56:            // Typhoon/KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059))
+               budget_av->budget.dvb_frontend =
+                       stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap);
+               if (budget_av->budget.dvb_frontend != NULL) {
+                       break;
+               }
+               break;
+
+       case 0x0020:            // KNC1 DVB-C budget (tda10021/Philips CU1216(tua6034))
+               budget_av->budget.dvb_frontend =
+                       tda10021_attach(&philips_cu1216_config,
+                                       &budget_av->budget.i2c_adap, read_pwm(budget_av));
+               if (budget_av->budget.dvb_frontend != NULL) {
+                       break;
+               }
+               break;
+
+       case 0x0030:            // KNC1 DVB-T budget (tda10046/Philips TU1216(tda6651tt))
+               budget_av->budget.dvb_frontend =
+                       tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap);
+               if (budget_av->budget.dvb_frontend != NULL) {
+                       break;
+               }
+               break;
+
+       case 0x1154:            // TerraTec Cinergy 1200 DVB-S (stv0299/Philips SU1278(tsa5059))
+               budget_av->budget.dvb_frontend =
+                       stv0299_attach(&cinergy_1200s_config, &budget_av->budget.i2c_adap);
+               if (budget_av->budget.dvb_frontend != NULL) {
+                       break;
+               }
+               break;
+
+       case 0x1156:            // Terratec Cinergy 1200 DVB-C (tda10021/Philips CU1216(tua6034))
+               budget_av->budget.dvb_frontend =
+                       tda10021_attach(&philips_cu1216_config,
+                                       &budget_av->budget.i2c_adap, read_pwm(budget_av));
+               if (budget_av->budget.dvb_frontend) {
+                       break;
+               }
+               break;
+
+       case 0x1157:            // Terratec Cinergy 1200 DVB-T (tda10046/Philips TU1216(tda6651tt))
+               budget_av->budget.dvb_frontend =
+                       tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap);
+               if (budget_av->budget.dvb_frontend) {
+                       break;
+               }
+               break;
+       }
+
+       if (budget_av->budget.dvb_frontend == NULL) {
+               printk("budget_av: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+                      budget_av->budget.dev->pci->vendor,
+                      budget_av->budget.dev->pci->device,
+                      budget_av->budget.dev->pci->subsystem_vendor,
+                      budget_av->budget.dev->pci->subsystem_device);
+       } else {
+               if (dvb_register_frontend
+                   (budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) {
+                       printk("budget-av: Frontend registration failed!\n");
+                       if (budget_av->budget.dvb_frontend->ops->release)
+                               budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+                       budget_av->budget.dvb_frontend = NULL;
+               }
+       }
+}
+
+
+static void budget_av_irq(struct saa7146_dev *dev, u32 * isr)
+{
+       struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
+
+       dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av);
+
+       if (*isr & MASK_10)
+               ttpci_budget_irq10_handler(dev, isr);
+}
+
 static int budget_av_detach (struct saa7146_dev *dev)
 {
        struct budget_av *budget_av = (struct budget_av*) dev->ext_priv;
        int err;
 
-       DEB_EE(("dev: %p\n",dev));
+       dprintk(2, "dev: %p\n", dev);
 
        if ( 1 == budget_av->has_saa7113 ) {
        saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
 
-       dvb_delay(200);
+               msleep(200);
 
        saa7146_unregister_device (&budget_av->vd, dev);
        }
 
+       if (budget_av->budget.ci_present)
+               ciintf_deinit(budget_av);
+
+       if (budget_av->budget.dvb_frontend != NULL)
+               dvb_unregister_frontend(budget_av->budget.dvb_frontend);
        err = ttpci_budget_deinit (&budget_av->budget);
 
        kfree (budget_av);
@@ -191,41 +802,35 @@ static int budget_av_detach (struct saa7146_dev *dev)
 
 static struct saa7146_ext_vv vv_data;
 
-static int budget_av_attach (struct saa7146_dev* dev,
-                     struct saa7146_pci_extension_data *info)
+static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 {
        struct budget_av *budget_av;
-       struct budget_info *bi = info->ext_priv;
        u8 *mac;
        int err;
 
-       DEB_EE(("dev: %p\n",dev));
-
-       if (bi->type != BUDGET_KNC1) {
-               return -ENODEV;
-       }
+       dprintk(2, "dev: %p\n", dev);
 
        if (!(budget_av = kmalloc(sizeof(struct budget_av), GFP_KERNEL)))
                return -ENOMEM;
 
        memset(budget_av, 0, sizeof(struct budget_av));
 
-       if ((err = ttpci_budget_init(&budget_av->budget, dev, info))) {
+       budget_av->budget.ci_present = 0;
+
+       dev->ext_priv = budget_av;
+
+       if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) {
                kfree(budget_av);
                return err;
        }
 
-       dev->ext_priv = budget_av;
-
        /* knc1 initialization */
        saa7146_write(dev, DD1_STREAM_B, 0x04000000);
        saa7146_write(dev, DD1_INIT, 0x07000600);
        saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26);
 
-       //test_knc_ci(av7110);
-
        saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
-       dvb_delay(500);
+       msleep(500);
 
        if ( 0 == saa7113_init(budget_av) ) {
                budget_av->has_saa7113 = 1;
@@ -236,9 +841,7 @@ static int budget_av_attach (struct saa7146_dev* dev,
                return err;
        }
 
-       if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1",
-                                          VFL_TYPE_GRABBER)))
-       {
+               if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
                /* fixme: proper cleanup here */
                ERR(("cannot register capture v4l2 device.\n"));
                return err;
@@ -259,19 +862,24 @@ static int budget_av_attach (struct saa7146_dev* dev,
        saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
 
        mac = budget_av->budget.dvb_adapter->proposed_mac;
-       if (i2c_readregs(budget_av->budget.i2c_bus, 0xa0, 0x30, mac, 6)) {
+       if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {
                printk("KNC1-%d: Could not read MAC from KNC1 card\n",
                                budget_av->budget.dvb_adapter->num);
                memset(mac, 0, 6);
-       }
-       else
+       } else {
                printk("KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
                                budget_av->budget.dvb_adapter->num,
                                mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-       return 0;
 }
 
+       budget_av->budget.dvb_adapter->priv = budget_av;
+       frontend_init(budget_av);
+
+       if (enable_ci)
+               ciintf_init(budget_av);
 
+       return 0;
+}
 
 #define KNC1_INPUTS 2
 static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
@@ -292,57 +900,47 @@ static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
        struct saa7146_dev *dev = fh->dev;
        struct budget_av *budget_av = (struct budget_av*) dev->ext_priv;
-/*
-       struct saa7146_vv *vv = dev->vv_data; 
-*/     
+
        switch(cmd) {
-       case VIDIOC_ENUMINPUT:
-       {
+       case VIDIOC_ENUMINPUT:{
                struct v4l2_input *i = arg;
                
-               DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
+               dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
                if( i->index < 0 || i->index >= KNC1_INPUTS) {
                        return -EINVAL;
                }
                memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
                return 0;
        }
-       case VIDIOC_G_INPUT:
-       {
+       case VIDIOC_G_INPUT:{
                int *input = (int *)arg;
 
                *input = budget_av->cur_input;
 
-               DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
+               dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
                return 0;               
        }       
-       case VIDIOC_S_INPUT:
-       {
+       case VIDIOC_S_INPUT:{
                int input = *(int *)arg;
-               DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
+               dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
                return saa7113_setinput (budget_av, input);
        }
        default:
-/*
-               DEB2(printk("does not handle this ioctl.\n"));
-*/
                return -ENOIOCTLCMD;
        }
        return 0;
 }
 
 static struct saa7146_standard standard[] = {
-       {
-               .name   = "PAL",        .id     = V4L2_STD_PAL,
+       {.name = "PAL",.id = V4L2_STD_PAL,
                .v_offset       = 0x17, .v_field        = 288,
                .h_offset       = 0x14, .h_pixels       = 680,                
-               .v_max_out      = 576,  .h_max_out      = 768
-       }, {
-               .name   = "NTSC",       .id     = V4L2_STD_NTSC,
+        .v_max_out = 576,.h_max_out = 768 },
+
+       {.name = "NTSC",.id = V4L2_STD_NTSC,
                .v_offset       = 0x16, .v_field        = 240,
                .h_offset       = 0x06, .h_pixels       = 708,
-               .v_max_out      = 480,  .h_max_out      = 640,
-       }
+        .v_max_out = 480,.h_max_out = 640, },
 };
 
 static struct saa7146_ext_vv vv_data = {
@@ -355,15 +953,22 @@ static struct saa7146_ext_vv vv_data = {
        .ioctl          = av_ioctl,
 };
 
-
-
 static struct saa7146_extension budget_extension;
 
-
-MAKE_BUDGET_INFO(knc1, "KNC1 DVB-S", BUDGET_KNC1);
+MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
+MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
+MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
+MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
+MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
 
 static struct pci_device_id pci_tbl [] = {
-       MAKE_EXTENSION_PCI(knc1, 0x1131, 0x4f56),
+       MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
+       MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
+       MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
+       MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
+       MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
+       MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
        {
                .vendor    = 0,
        }
@@ -380,24 +985,16 @@ static struct saa7146_extension budget_extension = {
        .detach         = budget_av_detach,
 
        .irq_mask       = MASK_10,
-       .irq_func       = ttpci_budget_irq10_handler,
+       .irq_func = budget_av_irq,
 };     
 
-
 static int __init budget_av_init(void) 
 {
-       DEB_EE((".\n"));
-
-       if (saa7146_register_extension(&budget_extension))
-               return -ENODEV;
-       
-       return 0;
+       return saa7146_register_extension(&budget_extension);
 }
 
-
 static void __exit budget_av_exit(void)
 {
-       DEB_EE((".\n"));
        saa7146_unregister_extension(&budget_extension); 
 }
 
@@ -407,5 +1004,6 @@ module_exit(budget_av_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
 MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
-                  "budget PCI DVB w/ analog input (e.g. the KNC cards)");
-
+                  "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)");
+module_param_named(enable_ci, enable_ci, int, 0644);
+MODULE_PARM_DESC(enable_ci, "Turn on/off CI module (default:off).");
index 30c8065..898a8bf 100644 (file)
 #include <linux/input.h>
 #include <linux/spinlock.h>
 
-#include "dvb_functions.h"
 #include "dvb_ca_en50221.h"
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include "input_fake.h"
-#endif
+#include "stv0299.h"
+#include "tda1004x.h"
 
 #define DEBIADDR_IR            0x1234
 #define DEBIADDR_CICONTROL     0x0000
@@ -69,70 +66,11 @@ struct budget_ci {
        struct input_dev input_dev;
        struct tasklet_struct msp430_irq_tasklet;
        struct tasklet_struct ciintf_irq_tasklet;
-       spinlock_t debilock;
        int slot_status;
        struct dvb_ca_en50221 ca;
        char ir_dev_name[50];
 };
 
-static u32 budget_debiread (struct budget_ci* budget_ci, u32 config, int addr, int count)
-{
-       struct saa7146_dev *saa = budget_ci->budget.dev;
-       u32 result = 0;
-
-       if (count > 4 || count <= 0)
-               return 0;
-
-       spin_lock(&budget_ci->debilock);
-
-       if (saa7146_wait_for_debi_done(saa) < 0) {
-               spin_unlock(&budget_ci->debilock);
-               return 0;
-       }
-
-       saa7146_write (saa, DEBI_COMMAND,
-                      (count << 17) | 0x10000 | (addr & 0xffff));
-       saa7146_write(saa, DEBI_CONFIG, config);
-       saa7146_write(saa, DEBI_PAGE, 0);
-       saa7146_write(saa, MC2, (2 << 16) | 2);
-
-       saa7146_wait_for_debi_done(saa);
-
-       result = saa7146_read(saa, 0x88);
-       result &= (0xffffffffUL >> ((4 - count) * 8));
-
-       spin_unlock(&budget_ci->debilock);
-       return result;
-}
-
-static u8 budget_debiwrite (struct budget_ci* budget_ci, u32 config, int addr, int count, u32 value)
-{
-       struct saa7146_dev *saa = budget_ci->budget.dev;
-
-       if (count > 4 || count <= 0)
-               return 0;
-
-       spin_lock(&budget_ci->debilock);
-
-       if (saa7146_wait_for_debi_done(saa) < 0) {
-               spin_unlock(&budget_ci->debilock);
-               return 0;
-       }
-
-       saa7146_write (saa, DEBI_COMMAND,
-                      (count << 17) | 0x00000 | (addr & 0xffff));
-       saa7146_write(saa, DEBI_CONFIG, config);
-       saa7146_write(saa, DEBI_PAGE, 0);
-       saa7146_write(saa, DEBI_AD, value);
-       saa7146_write(saa, MC2, (2 << 16) | 2);
-
-       saa7146_wait_for_debi_done(saa);
-
-       spin_unlock(&budget_ci->debilock);
-       return 0;
-}
-
-
 /* from reading the following remotes:
    Zenith Universal 7 / TV Mode 807 / VCR Mode 837
    Hauppauge (from NOVA-CI-s box product)
@@ -209,7 +147,8 @@ static void msp430_ir_interrupt (unsigned long data)
 {
        struct budget_ci *budget_ci = (struct budget_ci*) data;
        struct input_dev *dev = &budget_ci->input_dev;
-       unsigned int code = budget_debiread(budget_ci, DEBINOSWAP, DEBIADDR_IR, 2) >> 8;
+       unsigned int code =
+               ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
 
        if (code & 0x40) {
                code &= 0x3f;
@@ -224,8 +163,7 @@ static void msp430_ir_interrupt (unsigned long data)
                }
 
                if (!key_map[code]) {
-                       printk ("DVB (%s): no key for %02x!\n",
-                               __FUNCTION__, code);
+                       printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
                        return;
                        }
 
@@ -284,79 +222,98 @@ static void msp430_ir_deinit (struct budget_ci *budget_ci)
        input_unregister_device(dev);
 }
 
-static int ciintf_read_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address) {
+static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
+{
        struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 
-       if (slot != 0) return -EINVAL;
+       if (slot != 0)
+               return -EINVAL;
 
-       return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1);
+       return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
+                                    DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
 }
 
-static int ciintf_write_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address, u8 value) {
+static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
+{
        struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 
-       if (slot != 0) return -EINVAL;
+       if (slot != 0)
+               return -EINVAL;
 
-       return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1, value);
+       return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
+                                     DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
 }
 
-static int ciintf_read_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address) {
+static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
+{
        struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 
-       if (slot != 0) return -EINVAL;
+       if (slot != 0)
+               return -EINVAL;
 
-       return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1);
+       return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
+                                    DEBIADDR_IO | (address & 3), 1, 1, 0);
 }
 
-static int ciintf_write_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value) {
+static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
+{
        struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 
-       if (slot != 0) return -EINVAL;
+       if (slot != 0)
+               return -EINVAL;
 
-       return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1, value);
+       return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
+                                     DEBIADDR_IO | (address & 3), 1, value, 1, 0);
 }
 
-static int ciintf_slot_reset(struct dvb_ca_en50221* ca, int slot) {
+static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
        struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
        struct saa7146_dev *saa = budget_ci->budget.dev;
 
-       if (slot != 0) return -EINVAL;
+       if (slot != 0)
+               return -EINVAL;
 
        // trigger on RISING edge during reset so we know when READY is re-asserted
        saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
        budget_ci->slot_status = SLOTSTATUS_RESET;
-       budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
-       dvb_delay(1);
-       budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
+       ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
+       msleep(1);
+       ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+                              CICONTROL_RESET, 1, 0);
 
        saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
        ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
        return 0;
 }
 
-static int ciintf_slot_shutdown(struct dvb_ca_en50221* ca, int slot) {
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
        struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
        struct saa7146_dev *saa = budget_ci->budget.dev;
 
-       if (slot != 0) return -EINVAL;
+       if (slot != 0)
+               return -EINVAL;
 
        saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
        ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
        return 0;
 }
 
-static int ciintf_slot_ts_enable(struct dvb_ca_en50221* ca, int slot) {
+static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
        struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
        struct saa7146_dev *saa = budget_ci->budget.dev;
        int tmp;
 
-       if (slot != 0) return -EINVAL;
-
+       if (slot != 0)
+               return -EINVAL;
 
        saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
 
-       tmp = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
-       budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, tmp | CICONTROL_ENABLETS);
+       tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
+       ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+                              tmp | CICONTROL_ENABLETS, 1, 0);
 
        ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
        return 0;
@@ -370,20 +327,21 @@ static void ciintf_interrupt (unsigned long data)
        unsigned int flags;
 
        // ensure we don't get spurious IRQs during initialisation
-       if (!budget_ci->budget.ci_present) return;
+       if (!budget_ci->budget.ci_present)
+               return;
 
-       flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
+       // read the CAM status
+       flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
+       if (flags & CICONTROL_CAMDETECT) {
 
-       // always set the GPIO mode back to "normal", in case the card is
-       // yanked at an inopportune moment
+               // GPIO should be set to trigger on falling edge if a CAM is present
        saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
 
-       if (flags & CICONTROL_CAMDETECT) {
-
                if (budget_ci->slot_status & SLOTSTATUS_NONE) {
                        // CAM insertion IRQ
                        budget_ci->slot_status = SLOTSTATUS_PRESENT;
-                       dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_INSERTED);
+                       dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
+                                                    DVB_CA_EN50221_CAMCHANGE_INSERTED);
 
                } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
                        // CAM ready (reset completed)
@@ -395,9 +353,18 @@ static void ciintf_interrupt (unsigned long data)
                        dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
                }
        } else {
+
+               // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
+               // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
+               // the CAM might not actually be ready yet.
+               saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+
+               // generate a CAM removal IRQ if we haven't already
                if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
+                       // CAM removal IRQ
                        budget_ci->slot_status = SLOTSTATUS_NONE;
-                       dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_REMOVED);
+                       dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
+                                                    DVB_CA_EN50221_CAMCHANGE_REMOVED);
                }
        }
 }
@@ -414,18 +381,18 @@ static int ciintf_init(struct budget_ci* budget_ci)
        saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
 
        // test if it is there
-       if ((budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CIVERSION, 1) & 0xa0) != 0xa0) {
+       if ((ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0) & 0xa0) != 0xa0) {
                result = -ENODEV;
                goto error;
        }
-
        // determine whether a CAM is present or not
-       flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
+       flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
        budget_ci->slot_status = SLOTSTATUS_NONE;
-       if (flags & CICONTROL_CAMDETECT) budget_ci->slot_status = SLOTSTATUS_PRESENT;
-
+       if (flags & CICONTROL_CAMDETECT)
+               budget_ci->slot_status = SLOTSTATUS_PRESENT;
 
        // register CI interface
+       budget_ci->ca.owner = THIS_MODULE;
        budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
        budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
        budget_ci->ca.read_cam_control = ciintf_read_cam_control;
@@ -438,17 +405,21 @@ static int ciintf_init(struct budget_ci* budget_ci)
                                          &budget_ci->ca,
                                          DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
                                          DVB_CA_EN50221_FLAG_IRQ_FR |
-                                         DVB_CA_EN50221_FLAG_IRQ_DA,
-                                 1)) != 0) {
+                                         DVB_CA_EN50221_FLAG_IRQ_DA, 1)) != 0) {
                printk("budget_ci: CI interface detected, but initialisation failed.\n");
                goto error;
        }
 
        // Setup CI slot IRQ
        tasklet_init (&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
+       if (budget_ci->slot_status != SLOTSTATUS_NONE) {
        saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
+       } else {
+               saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+       }
        saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
-       budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
+       ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+                              CICONTROL_RESET, 1, 0);
 
        // success!
        printk("budget_ci: CI interface initialised\n");
@@ -456,7 +427,8 @@ static int ciintf_init(struct budget_ci* budget_ci)
 
        // forge a fake CI IRQ so the CAM state is setup correctly
        flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-       if (budget_ci->slot_status != SLOTSTATUS_NONE) flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
+       if (budget_ci->slot_status != SLOTSTATUS_NONE)
+               flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
        dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
 
        return 0;
@@ -474,9 +446,10 @@ static void ciintf_deinit(struct budget_ci* budget_ci)
        saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
        saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
        tasklet_kill(&budget_ci->ciintf_irq_tasklet);
-       budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
-       dvb_delay(1);
-       budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
+       ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
+       msleep(1);
+       ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+                              CICONTROL_RESET, 1, 0);
 
        // disable TS data stream to CI interface
        saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
@@ -492,7 +465,7 @@ static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr)
 {
         struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv;
 
-        DEB_EE(("dev: %p, budget_ci: %p\n", dev, budget_ci));
+       dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
 
         if (*isr & MASK_06)
                 tasklet_schedule (&budget_ci->msp430_irq_tasklet);
@@ -505,9 +478,426 @@ static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr)
 }
 
 
+static u8 alps_bsru6_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x00,
+       0x03, 0x00,
+       0x04, 0x7d,             /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+       0x05, 0x35,             /* I2CT = 0, SCLT = 1, SDAT = 1 */
+       0x06, 0x40,             /* DAC not used, set to high impendance mode */
+       0x07, 0x00,             /* DAC LSB */
+       0x08, 0x40,             /* DiSEqC off, LNB power on OP2/LOCK pin on */
+       0x09, 0x00,             /* FIFO */
+       0x0c, 0x51,             /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+       0x0d, 0x82,             /* DC offset compensation = ON, beta_agc1 = 2 */
+       0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
+       0x10, 0x3f,             // AGC2  0x3d
+       0x11, 0x84,
+       0x12, 0xb5,             // Lock detect: -64  Carrier freq detect:on
+       0x15, 0xc9,             // lock detector threshold
+       0x16, 0x00,
+       0x17, 0x00,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1a, 0x00,
+       0x1f, 0x50,
+       0x20, 0x00,
+       0x21, 0x00,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x28, 0x00,             // out imp: normal  out type: parallel FEC mode:0
+       0x29, 0x1e,             // 1/2 threshold
+       0x2a, 0x14,             // 2/3 threshold
+       0x2b, 0x0f,             // 3/4 threshold
+       0x2c, 0x09,             // 5/6 threshold
+       0x2d, 0x05,             // 7/8 threshold
+       0x2e, 0x01,
+       0x31, 0x1f,             // test all FECs
+       0x32, 0x19,             // viterbi and synchro search
+       0x33, 0xfc,             // rs control
+       0x34, 0x93,             // error control
+       0x0f, 0x52,
+       0xff, 0xff
+};
+
+static int alps_bsru6_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 alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+       u8 buf[4];
+       u32 div;
+       struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+       if ((params->frequency < 950000) || (params->frequency > 2150000))
+               return -EINVAL;
+
+       div = (params->frequency + (125 - 1)) / 125;    // round correctly
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+       buf[3] = 0xC4;
+
+       if (params->frequency > 1530000)
+               buf[3] = 0xc0;
+
+       if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+       .demod_address = 0x68,
+       .inittab = alps_bsru6_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .enhanced_tuning = 0,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = alps_bsru6_set_symbol_rate,
+       .pll_set = alps_bsru6_pll_set,
+};
+
+
+
+
+static u8 philips_su1278_tt_inittab[] = {
+       0x01, 0x0f,
+       0x02, 0x30,
+       0x03, 0x00,
+       0x04, 0x5b,
+       0x05, 0x85,
+       0x06, 0x02,
+       0x07, 0x00,
+       0x08, 0x02,
+       0x09, 0x00,
+       0x0C, 0x01,
+       0x0D, 0x81,
+       0x0E, 0x44,
+       0x0f, 0x14,
+       0x10, 0x3c,
+       0x11, 0x84,
+       0x12, 0xda,
+       0x13, 0x97,
+       0x14, 0x95,
+       0x15, 0xc9,
+       0x16, 0x19,
+       0x17, 0x8c,
+       0x18, 0x59,
+       0x19, 0xf8,
+       0x1a, 0xfe,
+       0x1c, 0x7f,
+       0x1d, 0x00,
+       0x1e, 0x00,
+       0x1f, 0x50,
+       0x20, 0x00,
+       0x21, 0x00,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x28, 0x00,
+       0x29, 0x28,
+       0x2a, 0x14,
+       0x2b, 0x0f,
+       0x2c, 0x09,
+       0x2d, 0x09,
+       0x31, 0x1f,
+       0x32, 0x19,
+       0x33, 0xfc,
+       0x34, 0x93,
+       0xff, 0xff
+};
+
+static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+       stv0299_writereg(fe, 0x0e, 0x44);
+       if (srate >= 10000000) {
+               stv0299_writereg(fe, 0x13, 0x97);
+               stv0299_writereg(fe, 0x14, 0x95);
+               stv0299_writereg(fe, 0x15, 0xc9);
+               stv0299_writereg(fe, 0x17, 0x8c);
+               stv0299_writereg(fe, 0x1a, 0xfe);
+               stv0299_writereg(fe, 0x1c, 0x7f);
+               stv0299_writereg(fe, 0x2d, 0x09);
+       } else {
+               stv0299_writereg(fe, 0x13, 0x99);
+               stv0299_writereg(fe, 0x14, 0x8d);
+               stv0299_writereg(fe, 0x15, 0xce);
+               stv0299_writereg(fe, 0x17, 0x43);
+               stv0299_writereg(fe, 0x1a, 0x1d);
+               stv0299_writereg(fe, 0x1c, 0x12);
+               stv0299_writereg(fe, 0x2d, 0x05);
+       }
+       stv0299_writereg(fe, 0x0e, 0x23);
+       stv0299_writereg(fe, 0x0f, 0x94);
+       stv0299_writereg(fe, 0x10, 0x39);
+       stv0299_writereg(fe, 0x15, 0xc9);
+
+       stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+       stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+       stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
+
+       return 0;
+}
+
+static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
+                                    struct dvb_frontend_parameters *params)
+{
+       struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+       u32 div;
+       u8 buf[4];
+       struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+       if ((params->frequency < 950000) || (params->frequency > 2150000))
+               return -EINVAL;
+
+       div = (params->frequency + (500 - 1)) / 500;    // round correctly
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
+       buf[3] = 0x20;
+
+       if (params->u.qpsk.symbol_rate < 4000000)
+               buf[3] |= 1;
+
+       if (params->frequency < 1250000)
+               buf[3] |= 0;
+       else if (params->frequency < 1550000)
+               buf[3] |= 0x40;
+       else if (params->frequency < 2050000)
+               buf[3] |= 0x80;
+       else if (params->frequency < 2150000)
+               buf[3] |= 0xC0;
+
+       if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static struct stv0299_config philips_su1278_tt_config = {
+
+       .demod_address = 0x68,
+       .inittab = philips_su1278_tt_inittab,
+       .mclk = 64000000UL,
+       .invert = 0,
+       .enhanced_tuning = 1,
+       .skip_reinit = 1,
+       .lock_output = STV0229_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 50,
+       .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
+       .pll_set = philips_su1278_tt_pll_set,
+};
+
+
+
+static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
+{
+       struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+       static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+       static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+       struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = td1316_init,.len =
+                       sizeof(td1316_init) };
+
+       // setup PLL configuration
+       if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
+               return -EIO;
+       msleep(1);
+
+       // disable the mc44BC374c (do not check for errors)
+       tuner_msg.addr = 0x65;
+       tuner_msg.buf = disable_mc44BC374c;
+       tuner_msg.len = sizeof(disable_mc44BC374c);
+       if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+               i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
+       }
+
+       return 0;
+}
+
+static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+       u8 tuner_buf[4];
+       struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
+       int tuner_frequency = 0;
+       u8 band, cp, filter;
+
+       // determine charge pump
+       tuner_frequency = params->frequency + 36130000;
+       if (tuner_frequency < 87000000)
+               return -EINVAL;
+       else if (tuner_frequency < 130000000)
+               cp = 3;
+       else if (tuner_frequency < 160000000)
+               cp = 5;
+       else if (tuner_frequency < 200000000)
+               cp = 6;
+       else if (tuner_frequency < 290000000)
+               cp = 3;
+       else if (tuner_frequency < 420000000)
+               cp = 5;
+       else if (tuner_frequency < 480000000)
+               cp = 6;
+       else if (tuner_frequency < 620000000)
+               cp = 3;
+       else if (tuner_frequency < 830000000)
+               cp = 5;
+       else if (tuner_frequency < 895000000)
+               cp = 7;
+       else
+               return -EINVAL;
+
+       // determine band
+       if (params->frequency < 49000000)
+               return -EINVAL;
+       else if (params->frequency < 159000000)
+               band = 1;
+       else if (params->frequency < 444000000)
+               band = 2;
+       else if (params->frequency < 861000000)
+               band = 4;
+       else
+               return -EINVAL;
+
+       // setup PLL filter and TDA9889
+       switch (params->u.ofdm.bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               tda1004x_write_byte(fe, 0x0C, 0x14);
+               filter = 0;
+               break;
+
+       case BANDWIDTH_7_MHZ:
+               tda1004x_write_byte(fe, 0x0C, 0x80);
+               filter = 0;
+               break;
+
+       case BANDWIDTH_8_MHZ:
+               tda1004x_write_byte(fe, 0x0C, 0x14);
+               filter = 1;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       // calculate divisor
+       // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
+       tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+
+       // setup tuner buffer
+       tuner_buf[0] = tuner_frequency >> 8;
+       tuner_buf[1] = tuner_frequency & 0xff;
+       tuner_buf[2] = 0xca;
+       tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+       if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
+               return -EIO;
+
+       msleep(1);
+       return 0;
+}
+
+static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
+                                            const struct firmware **fw, char *name)
+{
+       struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+
+       return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
+}
+
+static struct tda1004x_config philips_tdm1316l_config = {
+
+       .demod_address = 0x8,
+       .invert = 0,
+       .invert_oclk = 0,
+       .pll_init = philips_tdm1316l_pll_init,
+       .pll_set = philips_tdm1316l_pll_set,
+       .request_firmware = philips_tdm1316l_request_firmware,
+};
+
+
+
+static void frontend_init(struct budget_ci *budget_ci)
+{
+       switch (budget_ci->budget.dev->pci->subsystem_device) {
+       case 0x100c:            // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
+               budget_ci->budget.dvb_frontend =
+                       stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
+               if (budget_ci->budget.dvb_frontend) {
+                       break;
+               }
+               break;
+
+       case 0x100f:            // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
+               budget_ci->budget.dvb_frontend =
+                       stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
+               if (budget_ci->budget.dvb_frontend) {
+                       break;
+               }
+               break;
+
+       case 0x1011:            // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+               budget_ci->budget.dvb_frontend =
+                       tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+               if (budget_ci->budget.dvb_frontend) {
+                       break;
+               }
+               break;
+       }
+
+       if (budget_ci->budget.dvb_frontend == NULL) {
+               printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+                      budget_ci->budget.dev->pci->vendor,
+                      budget_ci->budget.dev->pci->device,
+                      budget_ci->budget.dev->pci->subsystem_vendor,
+                      budget_ci->budget.dev->pci->subsystem_device);
+       } else {
+               if (dvb_register_frontend
+                   (budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
+                       printk("budget-ci: Frontend registration failed!\n");
+                       if (budget_ci->budget.dvb_frontend->ops->release)
+                               budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+                       budget_ci->budget.dvb_frontend = NULL;
+               }
+       }
+}
 
-static int budget_ci_attach (struct saa7146_dev* dev,
-                     struct saa7146_pci_extension_data *info)
+static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 {
        struct budget_ci *budget_ci;
        int err;
@@ -515,25 +905,26 @@ static int budget_ci_attach (struct saa7146_dev* dev,
        if (!(budget_ci = kmalloc (sizeof(struct budget_ci), GFP_KERNEL)))
                return -ENOMEM;
 
-       DEB_EE(("budget_ci: %p\n", budget_ci));
+       dprintk(2, "budget_ci: %p\n", budget_ci);
 
-       spin_lock_init(&budget_ci->debilock);
        budget_ci->budget.ci_present = 0;
 
-       if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) {
+       dev->ext_priv = budget_ci;
+
+       if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
                kfree (budget_ci);
                return err;
        }
 
-       dev->ext_priv = budget_ci;
-
        tasklet_init (&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
                      (unsigned long) budget_ci);
 
        msp430_ir_init (budget_ci);
 
-       // UNCOMMENT TO TEST CI INTERFACE
-//     ciintf_init(budget_ci);
+       ciintf_init(budget_ci);
+
+       budget_ci->budget.dvb_adapter->priv = budget_ci;
+       frontend_init(budget_ci);
 
        return 0;
 }
@@ -546,8 +937,10 @@ static int budget_ci_detach (struct saa7146_dev* dev)
        struct saa7146_dev *saa = budget_ci->budget.dev;
        int err;
 
-       if (budget_ci->budget.ci_present) ciintf_deinit(budget_ci);
-
+       if (budget_ci->budget.ci_present)
+               ciintf_deinit(budget_ci);
+       if (budget_ci->budget.dvb_frontend)
+               dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
        err = ttpci_budget_deinit (&budget_ci->budget);
 
        tasklet_kill (&budget_ci->msp430_irq_tasklet);
@@ -599,10 +992,8 @@ static int __init budget_ci_init(void)
        return saa7146_register_extension(&budget_extension);
 }
 
-
 static void __exit budget_ci_exit(void)
 {
-       DEB_EE((".\n"));
        saa7146_unregister_extension(&budget_extension); 
 }
 
index 15cf744..bba2822 100644 (file)
  * the project's page is at http://www.linuxtv.org/dvb/
  */
 
+#include <linux/moduleparam.h>
+
 #include "budget.h"
 #include "ttpci-eeprom.h"
 
-int budget_debug = 0;
+int budget_debug;
+
+module_param_named(debug, budget_debug, int, 0644);
+MODULE_PARM_DESC(budget_debug, "Turn on/off budget debugging (default:off).");
 
 /****************************************************************************
  * TT budget / WinTV Nova
@@ -45,13 +50,13 @@ int budget_debug = 0;
 
 static int stop_ts_capture(struct budget *budget)
 {
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
 
         if (--budget->feeding)
                 return budget->feeding;
 
         saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off
-       IER_DISABLE(budget->dev, MASK_10);
+       SAA7146_IER_DISABLE(budget->dev, MASK_10);
         return 0;
 }
 
@@ -60,7 +65,7 @@ static int start_ts_capture (struct budget *budget)
 {
         struct saa7146_dev *dev=budget->dev;
 
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
 
         if (budget->feeding) 
                 return ++budget->feeding;
@@ -69,8 +74,7 @@ static int start_ts_capture (struct budget *budget)
 
         memset(budget->grabbing, 0x00, TS_HEIGHT*TS_WIDTH);
 
-        saa7146_write(dev, PCI_BT_V1, 0x001c0000 |
-            (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
+       saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
 
         budget->tsf=0xff;
         budget->ttbp=0;
@@ -120,7 +124,7 @@ static int start_ts_capture (struct budget *budget)
        saa7146_write(dev, MC2, (MASK_04 | MASK_20));
        saa7146_write(dev, MC1, (MASK_04 | MASK_20)); // DMA3 on
 
-       IER_ENABLE(budget->dev, MASK_10); // VPE
+       SAA7146_IER_ENABLE(budget->dev, MASK_10);       // VPE
 
         return ++budget->feeding;
 }
@@ -145,14 +149,87 @@ static void vpeirq (unsigned long data)
                return;
 
         if (newdma > olddma) { /* no wraparound, dump olddma..newdma */
-                        dvb_dmx_swfilter_packets(&budget->demux, 
-                               mem+olddma, (newdma-olddma) / 188);
+               dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (newdma - olddma) / 188);
         } else { /* wraparound, dump olddma..buflen and 0..newdma */
-                       dvb_dmx_swfilter_packets(&budget->demux,
-                               mem+olddma, (TS_BUFLEN-olddma) / 188);
-                        dvb_dmx_swfilter_packets(&budget->demux,
-                                mem, newdma / 188);
+               dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
+               dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188);
+       }
         }
+
+
+int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
+                         int uselocks, int nobusyloop)
+{
+       struct saa7146_dev *saa = budget->dev;
+       int result = 0;
+       unsigned long flags = 0;
+
+       if (count > 4 || count <= 0)
+               return 0;
+
+       if (uselocks)
+               spin_lock_irqsave(&budget->debilock, flags);
+
+       if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+               if (uselocks)
+                       spin_unlock_irqrestore(&budget->debilock, flags);
+               return result;
+       }
+
+       saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
+       saa7146_write(saa, DEBI_CONFIG, config);
+       saa7146_write(saa, DEBI_PAGE, 0);
+       saa7146_write(saa, MC2, (2 << 16) | 2);
+
+       if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+               if (uselocks)
+                       spin_unlock_irqrestore(&budget->debilock, flags);
+               return result;
+       }
+
+       result = saa7146_read(saa, DEBI_AD);
+       result &= (0xffffffffUL >> ((4 - count) * 8));
+
+       if (uselocks)
+               spin_unlock_irqrestore(&budget->debilock, flags);
+
+       return result;
+}
+
+int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
+                          int count, u32 value, int uselocks, int nobusyloop)
+{
+       struct saa7146_dev *saa = budget->dev;
+       unsigned long flags = 0;
+       int result;
+
+       if (count > 4 || count <= 0)
+               return 0;
+
+       if (uselocks)
+               spin_lock_irqsave(&budget->debilock, flags);
+
+       if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+               if (uselocks)
+                       spin_unlock_irqrestore(&budget->debilock, flags);
+               return result;
+       }
+
+       saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff));
+       saa7146_write(saa, DEBI_CONFIG, config);
+       saa7146_write(saa, DEBI_PAGE, 0);
+       saa7146_write(saa, DEBI_AD, value);
+       saa7146_write(saa, MC2, (2 << 16) | 2);
+
+       if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+               if (uselocks)
+                       spin_unlock_irqrestore(&budget->debilock, flags);
+               return result;
+       }
+
+       if (uselocks)
+               spin_unlock_irqrestore(&budget->debilock, flags);
+       return 0;
 }
 
 
@@ -166,7 +243,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
         struct budget *budget = (struct budget*) demux->priv;
        int status;
 
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
 
         if (!demux->dmx.frontend)
                 return -EINVAL;
@@ -183,7 +260,7 @@ static int budget_stop_feed(struct dvb_demux_feed *feed)
         struct budget *budget = (struct budget *) demux->priv;
        int status;
 
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
 
        spin_lock(&budget->feedlock);
        status = stop_ts_capture (budget);
@@ -197,7 +274,7 @@ static int budget_register(struct budget *budget)
         struct dvb_demux *dvbdemux=&budget->demux;
         int ret;
 
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
 
         dvbdemux->priv = (void *) budget;
 
@@ -226,13 +303,11 @@ static int budget_register(struct budget *budget)
                 return ret;
         
         budget->mem_frontend.source = DMX_MEMORY_FE;
-        ret=dvbdemux->dmx.add_frontend (&dvbdemux->dmx, 
-                                        &budget->mem_frontend);
+       ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend);
         if (ret<0)
                 return ret;
         
-        ret=dvbdemux->dmx.connect_frontend (&dvbdemux->dmx, 
-                                            &budget->hw_frontend);
+       ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend);
         if (ret < 0)
                 return ret;
 
@@ -246,7 +321,7 @@ static void budget_unregister(struct budget *budget)
 {
         struct dvb_demux *dvbdemux=&budget->demux;
 
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
 
        dvb_net_release(&budget->dvb_net);
 
@@ -258,17 +333,9 @@ static void budget_unregister(struct budget *budget)
         dvb_dmx_release(&budget->demux);
 }
 
-
-static int master_xfer (struct dvb_i2c_bus *i2c, const struct i2c_msg msgs[], int num)
-{
-       struct saa7146_dev *dev = i2c->data;
-       return saa7146_i2c_transfer(dev, msgs, num, 6);
-}
-
-
-int ttpci_budget_init (struct budget *budget,
-                      struct saa7146_dev* dev,
-                      struct saa7146_pci_extension_data *info)
+int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
+                     struct saa7146_pci_extension_data *info,
+                     struct module *owner)
 {
        int length = TS_WIDTH*TS_HEIGHT;
        int ret = 0;
@@ -276,12 +343,12 @@ int ttpci_budget_init (struct budget *budget,
 
        memset(budget, 0, sizeof(struct budget));
 
-       DEB_EE(("dev: %p, budget: %p\n", dev, budget));
+       dprintk(2, "dev: %p, budget: %p\n", dev, budget);
 
        budget->card = bi;
        budget->dev = (struct saa7146_dev *) dev;
 
-       dvb_register_adapter(&budget->dvb_adapter, budget->card->name, THIS_MODULE);
+       dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner);
 
        /* set dd1 stream a & b */
        saa7146_write(dev, DD1_STREAM_B, 0x00000000);
@@ -295,25 +362,33 @@ int ttpci_budget_init (struct budget *budget,
        else
                budget->video_port = BUDGET_VIDEO_PORTA;
        spin_lock_init(&budget->feedlock);
+       spin_lock_init(&budget->debilock);
 
        /* the Siemens DVB needs this if you want to have the i2c chips
            get recognized before the main driver is loaded */
        if (bi->type != BUDGET_FS_ACTIVY)
                saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
        
-       saa7146_i2c_adapter_prepare(dev, NULL, 0, SAA7146_I2C_BUS_BIT_RATE_120);
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+       budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
+#else
+       budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+#endif
+
+       strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
 
-       budget->i2c_bus = dvb_register_i2c_bus (master_xfer, dev,
-                                               budget->dvb_adapter, 0);
+       saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
+       strcpy(budget->i2c_adap.name, budget->card->name);
 
-       if (!budget->i2c_bus) {
+       if (i2c_add_adapter(&budget->i2c_adap) < 0) {
                dvb_unregister_adapter (budget->dvb_adapter);
                return -ENOMEM;
        }
 
-       ttpci_eeprom_parse_mac(budget->i2c_bus);
+       ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter->proposed_mac);
 
-       if( NULL == (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci,length,&budget->pt))) {
+       if (NULL ==
+           (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, length, &budget->pt))) {
                ret = -ENOMEM;
                goto err;
        }
@@ -334,12 +409,11 @@ int ttpci_budget_init (struct budget *budget,
                return 0;
        }
 err:
+       i2c_del_adapter(&budget->i2c_adap);
+
        if (budget->grabbing)
                vfree(budget->grabbing);
 
-       dvb_unregister_i2c_bus (master_xfer,budget->i2c_bus->adapter,
-                               budget->i2c_bus->id);
-
        dvb_unregister_adapter (budget->dvb_adapter);
 
        return ret;
@@ -350,12 +424,11 @@ int ttpci_budget_deinit (struct budget *budget)
 {
        struct saa7146_dev *dev = budget->dev;
 
-       DEB_EE(("budget: %p\n", budget));
+       dprintk(2, "budget: %p\n", budget);
 
        budget_unregister (budget);
 
-       dvb_unregister_i2c_bus (master_xfer, budget->i2c_bus->adapter,
-                               budget->i2c_bus->id);
+       i2c_del_adapter(&budget->i2c_adap);
 
        dvb_unregister_adapter (budget->dvb_adapter);
 
@@ -372,7 +445,7 @@ void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr)
 {
        struct budget *budget = (struct budget*)dev->ext_priv;
 
-       DEB_EE(("dev: %p, budget: %p\n",dev,budget));
+       dprintk(8, "dev: %p, budget: %p\n",dev,budget);
 
        if (*isr & MASK_10)
                tasklet_schedule (&budget->vpe_tasklet);
@@ -394,15 +467,13 @@ void ttpci_budget_set_video_port(struct saa7146_dev* dev, int video_port)
        spin_unlock(&budget->feedlock);
 }
 
-
-
+EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
+EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite);
 EXPORT_SYMBOL_GPL(ttpci_budget_init);
 EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
 EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
 EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
 EXPORT_SYMBOL_GPL(budget_debug);
 
-MODULE_PARM(budget_debug,"i");
 MODULE_LICENSE("GPL");
 
-
index 44118ec..7a9c682 100644 (file)
  * the project's page is at http://www.linuxtv.org/dvb/
  */
 
-#include "budget.h"
 #include "av7110.h"
 #include "av7110_hw.h"
+#include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "tda8083.h"
 
 #define budget_patch budget
 
@@ -51,7 +54,7 @@ static int budget_wdebi(struct budget_patch *budget, u32 config, int addr, u32 v
 {
         struct saa7146_dev *dev=budget->dev;
 
-        DEB_EE(("budget: %p\n", budget));
+        dprintk(2, "budget: %p\n", budget);
 
         if (count <= 0 || count > 4)
                 return -1;
@@ -71,7 +74,7 @@ static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int
 {
         int i;
 
-        DEB_EE(("budget: %p\n", budget));
+        dprintk(2, "budget: %p\n", budget);
 
         for (i = 2; i < length; i++)
                 budget_wdebi(budget, DEBINOSWAP, COMMAND + 2*i, (u32) buf[i], 2);
@@ -90,7 +93,7 @@ static void av7110_set22k(struct budget_patch *budget, int state)
 {
         u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0};
         
-        DEB_EE(("budget: %p\n", budget));
+        dprintk(2, "budget: %p\n", budget);
         budget_av7110_send_fw_cmd(budget, buf, 2);
 }
 
@@ -101,7 +104,7 @@ static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg,
         u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC),
                 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
-        DEB_EE(("budget: %p\n", budget));
+        dprintk(2, "budget: %p\n", budget);
 
         if (len>10)
                 len=10;
@@ -121,16 +124,11 @@ static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg,
         return 0;
 }
 
-
-int budget_patch_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-        struct budget_patch *budget = fe->before_after_data;
+       struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
 
-        DEB_EE(("budget: %p\n", budget));
-
-        switch (cmd) {
-        case FE_SET_TONE:
-                switch ((fe_sec_tone_mode_t) arg) {
+       switch (tone) {
                 case SEC_TONE_ON:
                         av7110_set22k (budget, 1);
                         break;
@@ -140,27 +138,232 @@ int budget_patch_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *
                 default:
                         return -EINVAL;
                 }
-                break;
 
-        case FE_DISEQC_SEND_MASTER_CMD:
+       return 0;
+}
+
+static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
         {
-                struct dvb_diseqc_master_cmd *cmd = arg;
+       struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
 
                 av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
-                break;
+
+       return 0;
         }
 
-        case FE_DISEQC_SEND_BURST:
-                av7110_send_diseqc_msg (budget, 0, NULL, (int) (long) arg);
-                break;
+static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+       struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
 
-        default:
-                return -EOPNOTSUPP;
+       av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
+
+       return 0;
         }
 
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+       u8 pwr = 0;
+       u8 buf[4];
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       u32 div = (params->frequency + 479500) / 125;
+
+       if (params->frequency > 2000000) pwr = 3;
+       else if (params->frequency > 1800000) pwr = 2;
+       else if (params->frequency > 1600000) pwr = 1;
+       else if (params->frequency > 1200000) pwr = 0;
+       else if (params->frequency >= 1100000) pwr = 1;
+       else pwr = 2;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = ((div & 0x18000) >> 10) | 0x95;
+       buf[3] = (pwr << 6) | 0x30;
+
+        // NOTE: since we're using a prescaler of 2, we set the
+       // divisor frequency to 62.5kHz and divide by 125 above
+
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+       return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config = {
+       .demod_address = 0x08,
+       .xin = 90100000UL,
+       .invert_pwm = 0,
+       .pll_set = alps_bsrv2_pll_set,
+};
+
+static u8 alps_bsru6_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x00,
+       0x03, 0x00,
+        0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+       0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+       0x06, 0x40,   /* DAC not used, set to high impendance mode */
+       0x07, 0x00,   /* DAC LSB */
+       0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+       0x09, 0x00,   /* FIFO */
+       0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+       0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+       0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+       0x10, 0x3f,   // AGC2  0x3d
+       0x11, 0x84,
+       0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+       0x15, 0xc9,   // lock detector threshold
+       0x16, 0x00,
+       0x17, 0x00,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1a, 0x00,
+       0x1f, 0x50,
+       0x20, 0x00,
+       0x21, 0x00,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+       0x29, 0x1e,  // 1/2 threshold
+       0x2a, 0x14,  // 2/3 threshold
+       0x2b, 0x0f,  // 3/4 threshold
+       0x2c, 0x09,  // 5/6 threshold
+       0x2d, 0x05,  // 7/8 threshold
+       0x2e, 0x01,
+       0x31, 0x1f,  // test all FECs
+       0x32, 0x19,  // viterbi and synchro search
+       0x33, 0xfc,  // rs control
+       0x34, 0x93,  // error control
+       0x0f, 0x52,
+       0xff, 0xff
+};
+
+static int alps_bsru6_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 alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+       u8 data[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+       if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+       div = (params->frequency + (125 - 1)) / 125; // round correctly
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+       data[3] = 0xC4;
+
+       if (params->frequency > 1530000) data[3] = 0xc0;
+
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+       return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+       .demod_address = 0x68,
+       .inittab = alps_bsru6_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .enhanced_tuning = 0,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = alps_bsru6_set_symbol_rate,
+       .pll_set = alps_bsru6_pll_set,
+};
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+       u32 div;
+       u8 data[4];
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+       div = params->frequency / 125;
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = 0x8e;
+       data[3] = 0x00;
+
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+       return 0;
+}
+
+struct tda8083_config grundig_29504_451_config = {
+       .demod_address = 0x68,
+       .pll_set = grundig_29504_451_pll_set,
+};
+
+static void frontend_init(struct budget_patch* budget)
+{
+       switch(budget->dev->pci->subsystem_device) {
+       case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+
+               // try the ALPS BSRV2 first of all
+               budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+                       budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+                       break;
+               }
+
+               // try the ALPS BSRU6 now
+               budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+                       budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+                       break;
+               }
+
+               // Try the grundig 29504-451
+               budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+                       budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+                       break;
+               }
+               break;
+       }
+
+       if (budget->dvb_frontend == NULL) {
+               printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+                      budget->dev->pci->vendor,
+                      budget->dev->pci->device,
+                      budget->dev->pci->subsystem_vendor,
+                      budget->dev->pci->subsystem_device);
+       } else {
+               if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+                       printk("budget-av: Frontend registration failed!\n");
+                       if (budget->dvb_frontend->ops->release)
+                               budget->dvb_frontend->ops->release(budget->dvb_frontend);
+                       budget->dvb_frontend = NULL;
+               }
+       }
+}
 
 static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
 {
@@ -171,9 +374,9 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
         if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
                 return -ENOMEM;
 
-        DEB_EE(("budget: %p\n",budget));
+        dprintk(2, "budget: %p\n", budget);
 
-        if ((err = ttpci_budget_init (budget, dev, info))) {
+        if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
                 kfree (budget);
                 return err;
         }
@@ -221,11 +424,11 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
         // Enable RPS1                                                  (rFC p33)
         saa7146_write(dev, MC1, (MASK_13 | MASK_29));
 
-        dvb_add_frontend_ioctls (budget->dvb_adapter,
-                budget_patch_diseqc_ioctl, NULL, budget);
-
         dev->ext_priv = budget;
 
+       budget->dvb_adapter->priv = budget;
+       frontend_init(budget);
+
         return 0;
 }
 
@@ -235,8 +438,7 @@ static int budget_patch_detach (struct saa7146_dev* dev)
         struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
         int err;
 
-        dvb_remove_frontend_ioctls (budget->dvb_adapter,
-                budget_patch_diseqc_ioctl, NULL);
+       if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
 
         err = ttpci_budget_deinit (budget);
 
@@ -251,10 +453,8 @@ static int __init budget_patch_init(void)
        return saa7146_register_extension(&budget_extension);
 }
 
-
 static void __exit budget_patch_exit(void)
 {
-        DEB_EE((".\n"));
         saa7146_unregister_extension(&budget_extension); 
 }
 
index fbf1d5a..9488c72 100644 (file)
  */
 
 #include "budget.h"
-#include "dvb_functions.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "ves1820.h"
+#include "l64781.h"
+#include "tda8083.h"
 
 static void Set22K (struct budget *budget, int state)
 {
        struct saa7146_dev *dev=budget->dev;
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
        saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
 }
 
@@ -52,7 +56,7 @@ static void Set22K (struct budget *budget, int state)
 static void DiseqcSendBit (struct budget *budget, int data)
 {
        struct saa7146_dev *dev=budget->dev;
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
 
        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
        udelay(data ? 500 : 1000);
@@ -65,7 +69,7 @@ static void DiseqcSendByte (struct budget *budget, int data)
 {
        int i, par=1, d;
 
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
 
        for (i=7; i>=0; i--) {
                d = (data>>i)&1;
@@ -82,7 +86,7 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
        struct saa7146_dev *dev=budget->dev;
        int i;
 
-       DEB_EE(("budget: %p\n",budget));
+       dprintk(2, "budget: %p\n", budget);
 
        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
        mdelay(16);
@@ -100,95 +104,374 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
                        udelay(12500);
                        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
                }
-               dvb_delay(20);
+               msleep(20);
        }
 
        return 0;
 }
 
+/*
+ *   Routines for the Fujitsu Siemens Activy budget card
+ *   22 kHz tone and DiSEqC are handled by the frontend.
+ *   Voltage must be set here.
+ */
+static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
+{
+       struct saa7146_dev *dev=budget->dev;
+
+       dprintk(2, "budget: %p\n", budget);
+
+       switch (voltage) {
+               case SEC_VOLTAGE_13:
+                       saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
+                       break;
+               case SEC_VOLTAGE_18:
+                       saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       return 0;
+}
 
-int budget_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
-       struct budget *budget = fe->before_after_data;
+       struct budget* budget = (struct budget*) fe->dvb->priv;
 
-       DEB_EE(("budget: %p\n",budget));
+       return SetVoltage_Activy (budget, voltage);
+}
 
-       switch (cmd) {
-       case FE_SET_TONE:
-               switch ((fe_sec_tone_mode_t) arg) {
+static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+       struct budget* budget = (struct budget*) fe->dvb->priv;
+
+       switch (tone) {
                case SEC_TONE_ON:
                        Set22K (budget, 1);
                        break;
                case SEC_TONE_OFF:
                        Set22K (budget, 0);
                        break;
+
                default:
                        return -EINVAL;
-               };
-               break;
+       }
 
-       case FE_DISEQC_SEND_MASTER_CMD:
+       return 0;
+}
+
+static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
        {
-               struct dvb_diseqc_master_cmd *cmd = arg;
+       struct budget* budget = (struct budget*) fe->dvb->priv;
 
                SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
-               break;
+
+       return 0;
        }
 
-       case FE_DISEQC_SEND_BURST:
-               SendDiSEqCMsg (budget, 0, NULL, (unsigned long)arg);
-               break;
+static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+       struct budget* budget = (struct budget*) fe->dvb->priv;
 
-       default:
-               return -EOPNOTSUPP;
-       };
+       SendDiSEqCMsg (budget, 0, NULL, minicmd);
 
        return 0;
 }
 
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       struct budget* budget = (struct budget*) fe->dvb->priv;
+       u8 pwr = 0;
+       u8 buf[4];
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       u32 div = (params->frequency + 479500) / 125;
+
+       if (params->frequency > 2000000) pwr = 3;
+       else if (params->frequency > 1800000) pwr = 2;
+       else if (params->frequency > 1600000) pwr = 1;
+       else if (params->frequency > 1200000) pwr = 0;
+       else if (params->frequency >= 1100000) pwr = 1;
+       else pwr = 2;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = ((div & 0x18000) >> 10) | 0x95;
+       buf[3] = (pwr << 6) | 0x30;
+
+        // NOTE: since we're using a prescaler of 2, we set the
+       // divisor frequency to 62.5kHz and divide by 125 above
+
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+       return 0;
+}
 
-/*
- *   Routines for the Fujitsu Siemens Activy budget card
- *   22 kHz tone and DiSEqC are handled by the frontend.
- *   Voltage must be set here.
- */
-static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
+static struct ves1x93_config alps_bsrv2_config =
 {
-       struct saa7146_dev *dev=budget->dev;
+       .demod_address = 0x08,
+       .xin = 90100000UL,
+       .invert_pwm = 0,
+       .pll_set = alps_bsrv2_pll_set,
+};
 
-       DEB_EE(("budget: %p\n",budget));
+static u8 alps_bsru6_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x00,
+       0x03, 0x00,
+        0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+       0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+       0x06, 0x40,   /* DAC not used, set to high impendance mode */
+       0x07, 0x00,   /* DAC LSB */
+       0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+       0x09, 0x00,   /* FIFO */
+       0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+       0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+       0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+       0x10, 0x3f,   // AGC2  0x3d
+       0x11, 0x84,
+       0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+       0x15, 0xc9,   // lock detector threshold
+       0x16, 0x00,
+       0x17, 0x00,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1a, 0x00,
+       0x1f, 0x50,
+       0x20, 0x00,
+       0x21, 0x00,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+       0x29, 0x1e,  // 1/2 threshold
+       0x2a, 0x14,  // 2/3 threshold
+       0x2b, 0x0f,  // 3/4 threshold
+       0x2c, 0x09,  // 5/6 threshold
+       0x2d, 0x05,  // 7/8 threshold
+       0x2e, 0x01,
+       0x31, 0x1f,  // test all FECs
+       0x32, 0x19,  // viterbi and synchro search
+       0x33, 0xfc,  // rs control
+       0x34, 0x93,  // error control
+       0x0f, 0x52,
+       0xff, 0xff
+};
 
-       switch (voltage) {
-               case SEC_VOLTAGE_13:
-                       saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
-                       break;
-               case SEC_VOLTAGE_18:
-                       saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
-                       break;
-               default:
-                       return -EINVAL;
+static int alps_bsru6_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 alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       struct budget* budget = (struct budget*) fe->dvb->priv;
+       u8 data[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+       if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+       div = (params->frequency + (125 - 1)) / 125; // round correctly
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+       data[3] = 0xC4;
+
+       if (params->frequency > 1530000) data[3] = 0xc0;
+
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
        return 0;
 }
 
+static struct stv0299_config alps_bsru6_config = {
+
+       .demod_address = 0x68,
+       .inittab = alps_bsru6_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .enhanced_tuning = 0,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = alps_bsru6_set_symbol_rate,
+       .pll_set = alps_bsru6_pll_set,
+};
 
-static int budget_ioctl_activy (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
-       struct budget *budget = fe->before_after_data;
+       struct budget* budget = (struct budget*) fe->dvb->priv;
+       u32 div;
+       u8 data[4];
+       struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       DEB_EE(("budget: %p\n",budget));
+       div = (params->frequency + 35937500 + 31250) / 62500;
 
-       switch (cmd) {
-               case FE_SET_VOLTAGE:
-                       return SetVoltage_Activy (budget, (fe_sec_voltage_t) arg);
-               default:
-                       return -EOPNOTSUPP;
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = 0x85 | ((div >> 10) & 0x60);
+       data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+       return 0;
+}
+
+static struct ves1820_config alps_tdbe2_config = {
+       .demod_address = 0x09,
+       .xin = 57840000UL,
+       .invert = 1,
+       .selagc = VES1820_SELAGC_SIGNAMPERR,
+       .pll_set = alps_tdbe2_pll_set,
+};
+
+static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       struct budget* budget = (struct budget*) fe->dvb->priv;
+       u32 div;
+       u8 cfg, cpump, band_select;
+       u8 data[4];
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+       div = (36125000 + params->frequency) / 166666;
+
+       cfg = 0x88;
+
+       if (params->frequency < 175000000) cpump = 2;
+       else if (params->frequency < 390000000) cpump = 1;
+       else if (params->frequency < 470000000) cpump = 2;
+       else if (params->frequency < 750000000) cpump = 1;
+       else cpump = 3;
+
+       if (params->frequency < 175000000) band_select = 0x0e;
+       else if (params->frequency < 470000000) band_select = 0x05;
+       else band_select = 0x03;
+
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = ((div >> 10) & 0x60) | cfg;
+       data[3] = (cpump << 6) | band_select;
+
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+       return 0;
        }
 
+static struct l64781_config grundig_29504_401_config = {
+       .demod_address = 0x55,
+       .pll_set = grundig_29504_401_pll_set,
+};
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       struct budget* budget = (struct budget*) fe->dvb->priv;
+       u32 div;
+       u8 data[4];
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+       div = params->frequency / 125;
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = 0x8e;
+       data[3] = 0x00;
+
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
        return 0;
 }
 
+static struct tda8083_config grundig_29504_451_config = {
+       .demod_address = 0x68,
+       .pll_set = grundig_29504_451_pll_set,
+};
+
+static u8 read_pwm(struct budget* budget)
+{
+       u8 b = 0xff;
+       u8 pwm;
+       struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+                                { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+        if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+               pwm = 0x48;
+
+       return pwm;
+}
+
+static void frontend_init(struct budget *budget)
+{
+       switch(budget->dev->pci->subsystem_device) {
+       case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
+
+               // try the ALPS BSRV2 first of all
+               budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+                       budget->dvb_frontend->ops->set_tone = budget_set_tone;
+                       break;
+               }
+
+               // try the ALPS BSRU6 now
+               budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+                       budget->dvb_frontend->ops->set_tone = budget_set_tone;
+                       break;
+               }
+               break;
+
+       case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+
+               budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
+               if (budget->dvb_frontend) break;
+               break;
+
+       case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
+
+               budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
+               if (budget->dvb_frontend) break;
+               break;
+
+       case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI (tda8083/Grundig 29504-451(tsa5522))
+
+               // grundig 29504-451
+                budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
+                       break;
+               }
+               break;
+       }
+
+       if (budget->dvb_frontend == NULL) {
+               printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+                      budget->dev->pci->vendor,
+                      budget->dev->pci->device,
+                      budget->dev->pci->subsystem_vendor,
+                      budget->dev->pci->subsystem_device);
+       } else {
+               if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+                       printk("budget: Frontend registration failed!\n");
+                       if (budget->dvb_frontend->ops->release)
+                               budget->dvb_frontend->ops->release(budget->dvb_frontend);
+                       budget->dvb_frontend = NULL;
+               }
+       }
+}
 
 static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
 {
@@ -200,22 +483,18 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_
                return -ENOMEM;
        }
 
-       DEB_EE(("dev:%p, info:%p, budget:%p\n",dev,info,budget));
+       dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget);
 
-       if ((err = ttpci_budget_init (budget, dev, info))) {
+       dev->ext_priv = budget;
+
+       if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
                printk("==> failed\n");
                kfree (budget);
                return err;
        }
 
-       if (budget->card->type == BUDGET_FS_ACTIVY)
-               dvb_add_frontend_ioctls (budget->dvb_adapter,
-                                budget_ioctl_activy, NULL, budget);
-       else
-       dvb_add_frontend_ioctls (budget->dvb_adapter,
-                                budget_diseqc_ioctl, NULL, budget);
-
-       dev->ext_priv = budget;
+       budget->dvb_adapter->priv = budget;
+       frontend_init(budget);
 
        return 0;
 }
@@ -226,12 +505,7 @@ static int budget_detach (struct saa7146_dev* dev)
        struct budget *budget = (struct budget*) dev->ext_priv;
        int err;
 
-       if (budget->card->type == BUDGET_FS_ACTIVY)
-               dvb_remove_frontend_ioctls (budget->dvb_adapter,
-                                   budget_ioctl_activy, NULL);
-       else
-       dvb_remove_frontend_ioctls (budget->dvb_adapter,
-                                   budget_diseqc_ioctl, NULL);
+       if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
 
        err = ttpci_budget_deinit (budget);
 
@@ -248,18 +522,14 @@ static struct saa7146_extension budget_extension;
 MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T  PCI",  BUDGET_TT);
-MAKE_BUDGET_INFO(satel,        "SATELCO Multimedia PCI",       BUDGET_TT_HW_DISEQC);
+/* MAKE_BUDGET_INFO(satel,     "SATELCO Multimedia PCI",       BUDGET_TT_HW_DISEQC); UNDEFINED HARDWARE - mail linuxtv.org list */
 MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY);
-/* Uncomment for Budget Patch */
-/*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/
 
 static struct pci_device_id pci_tbl[] = {
-       /* Uncomment for Budget Patch */
-       /*MAKE_EXTENSION_PCI(fs_1_3,0x13c2, 0x0000),*/
        MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
        MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
        MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
-       MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+/*     MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), UNDEFINED HARDWARE */
        MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61),
        {
                .vendor    = 0,
@@ -290,7 +560,6 @@ static int __init budget_init(void)
 
 static void __exit budget_exit(void)
 {
-       DEB_EE((".\n"));
        saa7146_unregister_extension(&budget_extension); 
 }
 
index 6be1d3b..726394c 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef __BUDGET_DVB__
 #define __BUDGET_DVB__
 
-#include <media/saa7146.h>
-
-#include "dvb_i2c.h"
 #include "dvb_frontend.h"
 #include "dvbdev.h"
 #include "demux.h"
@@ -12,8 +9,18 @@
 #include "dvb_filter.h"
 #include "dvb_net.h"
 
+#include <linux/module.h>
+#include <media/saa7146.h>
+
 extern int budget_debug;
 
+#ifdef dprintk
+#undef dprintk
+#endif
+
+#define dprintk(level,args...) \
+            do { if ((budget_debug & level)) { printk("%s: %s(): ",__stringify(KBUILD_MODNAME), __FUNCTION__); printk(args); } } while (0)
+
 struct budget_info {
        char *name;
        int type;
@@ -28,7 +35,7 @@ struct budget {
 
         struct saa7146_dev     *dev;
 
-       struct dvb_i2c_bus      *i2c_bus;       
+       struct i2c_adapter      i2c_adap;
        struct budget_info      *card;
 
        unsigned char           *grabbing;
@@ -55,7 +62,10 @@ struct budget {
 
        spinlock_t feedlock;
 
+       spinlock_t debilock;
+
         struct dvb_adapter       *dvb_adapter;
+       struct dvb_frontend *dvb_frontend;
        void                     *priv;
 };
 
@@ -76,19 +86,27 @@ static struct saa7146_pci_extension_data x_var = { \
 
 #define BUDGET_TT                 0
 #define BUDGET_TT_HW_DISEQC       1
-#define BUDGET_KNC1               2
 #define BUDGET_PATCH              3
 #define BUDGET_FS_ACTIVY          4
+#define BUDGET_CIN1200S                   5
+#define BUDGET_CIN1200C                   6
+#define BUDGET_CIN1200T                   7
+#define BUDGET_KNC1S              8
+#define BUDGET_KNC1C              9
+#define BUDGET_KNC1T              10
 
 #define BUDGET_VIDEO_PORTA         0
 #define BUDGET_VIDEO_PORTB         1
 
-extern int ttpci_budget_init (struct budget *budget,
-                             struct saa7146_dev* dev,
-                             struct saa7146_pci_extension_data *info);
+extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
+                            struct saa7146_pci_extension_data *info,
+                            struct module *owner);
 extern int ttpci_budget_deinit (struct budget *budget);
 extern void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr);
 extern void ttpci_budget_set_video_port(struct saa7146_dev* dev, int video_port);
+extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
+                                int uselocks, int nobusyloop);
+extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value,
+                                 int uselocks, int nobusyloop);
 
 #endif
-
index a17c828..0659c53 100644 (file)
@@ -35,9 +35,8 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/i2c.h>
 
-#include "dvb_i2c.h"
-#include "dvb_functions.h"
 
 #if 1
 #define dprintk(x...) do { printk(x); } while (0)
@@ -85,7 +84,7 @@ static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
         return 0;
 }
 
-static int ttpci_eeprom_read_encodedMAC(struct dvb_i2c_bus *i2c, u8 * encodedMAC)
+static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
 {
        int ret;
        u8 b0[] = { 0xcc };
@@ -97,7 +96,7 @@ static int ttpci_eeprom_read_encodedMAC(struct dvb_i2c_bus *i2c, u8 * encodedMAC
 
        /* dprintk("%s\n", __FUNCTION__); */
 
-       ret = i2c->xfer(i2c, msg, 2);
+       ret = i2c_transfer(adapter, msg, 2);
 
        if (ret != 2)           /* Assume EEPROM isn't there */
                return (-ENODEV);
@@ -106,36 +105,34 @@ static int ttpci_eeprom_read_encodedMAC(struct dvb_i2c_bus *i2c, u8 * encodedMAC
 }
 
 
-int ttpci_eeprom_parse_mac(struct dvb_i2c_bus *i2c)
+int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac)
 {
        int ret, i;
        u8 encodedMAC[20];
        u8 decodedMAC[6];
 
-       ret = ttpci_eeprom_read_encodedMAC(i2c, encodedMAC);
+       ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC);
 
        if (ret != 0) {         /* Will only be -ENODEV */
                dprintk("Couldn't read from EEPROM: not there?\n");
-               memset(i2c->adapter->proposed_mac, 0, 6);
+               memset(proposed_mac, 0, 6);
                return ret;
        }
 
        ret = getmac_tt(decodedMAC, encodedMAC);
        if( ret != 0 ) {
-               dprintk("%s adapter %i failed MAC signature check\n",
-                       i2c->adapter->name, i2c->adapter->num);
+               dprintk("adapter failed MAC signature check\n");
                dprintk("encoded MAC from EEPROM was " );
                for(i=0; i<19; i++) {
                        dprintk( "%.2x:", encodedMAC[i]);
                }
                dprintk("%.2x\n", encodedMAC[19]);
-               memset(i2c->adapter->proposed_mac, 0, 6);
+               memset(proposed_mac, 0, 6);
                return ret;
        }
 
-       memcpy(i2c->adapter->proposed_mac, decodedMAC, 6);
-       dprintk("%s adapter %i has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-               i2c->adapter->name, i2c->adapter->num,
+       memcpy(proposed_mac, decodedMAC, 6);
+       dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
                decodedMAC[0], decodedMAC[1], decodedMAC[2],
                decodedMAC[3], decodedMAC[4], decodedMAC[5]);
        return 0;
index 48df7ce..e2dc6cf 100644 (file)
@@ -25,8 +25,9 @@
 #ifndef __TTPCI_EEPROM_H__
 #define __TTPCI_EEPROM_H__
 
-#include "dvb_i2c.h"
+#include <linux/types.h>
+#include <linux/i2c.h>
 
-extern int ttpci_eeprom_parse_mac(struct dvb_i2c_bus *i2c);
+extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
 
 #endif
index c8bbbcc..b4d3322 100644 (file)
@@ -1,6 +1,10 @@
 config DVB_TTUSB_BUDGET
        tristate "Technotrend/Hauppauge Nova-USB devices"
        depends on DVB_CORE && USB
+       select DVB_CX22700
+       select DVB_TDA1004X
+       select DVB_TDA8083
+       select DVB_STV0299
        help
          Support for external USB adapters designed by Technotrend and
          produced by Hauppauge, shipped under the brand name 'Nova-USB'.
index a57b9ae..6ab97f6 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
index 287645d..95ee799 100644 (file)
@@ -1,7 +1,7 @@
 
 #include <asm/types.h>
 
-u8 dsp_bootcode [] = {
+static u8 dsp_bootcode [] = {
        0x08, 0xaa, 0x00, 0x18, 0x00, 0x03, 0x08, 0x00, 
        0x00, 0x10, 0x00, 0x00, 0x01, 0x80, 0x18, 0x5f, 
        0x00, 0x00, 0x01, 0x80, 0x77, 0x18, 0x2a, 0xeb, 
index 139d71e..61fabb6 100644 (file)
@@ -12,8 +12,10 @@ config DVB_TTUSB_DEC
          only compressed MPEG data over the USB bus, so you need
          an external software decoder to watch TV on your computer.      
 
-         The DEC devices require firmware in order to boot into a mode in
-         which they are slaves to the PC.  See
-         <file:Documentation/dvb/ttusb-dec.txt> for details.
+          This driver needs external firmware. Please use the commands
+          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
+          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
+          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
+          download/extract them, and then copy them to /usr/lib/hotplug/firmware.
 
          Say Y if you own such a device and want to use it.
index bf4e387..b41bf1f 100644 (file)
@@ -1,3 +1,3 @@
-obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o
+obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
 
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
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");
index a1a3a0d..0bcd953 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
     bt848.h - Bt848 register offsets
 
     Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
 #define _BT848_H_
 
 #ifndef PCI_VENDOR_ID_BROOKTREE
-#define PCI_VENDOR_ID_BROOKTREE 0x109e 
+#define PCI_VENDOR_ID_BROOKTREE 0x109e
 #endif
 #ifndef PCI_DEVICE_ID_BT848
-#define PCI_DEVICE_ID_BT848     0x350  
+#define PCI_DEVICE_ID_BT848     0x350
 #endif
 #ifndef PCI_DEVICE_ID_BT849
 #define PCI_DEVICE_ID_BT849     0x351
@@ -50,7 +50,7 @@
 #define BT848_DSTATUS_LOF      (1<<1)
 #define BT848_DSTATUS_COF      (1<<0)
 
-#define BT848_IFORM            0x004  
+#define BT848_IFORM            0x004
 #define BT848_IFORM_HACTIVE    (1<<7)
 #define BT848_IFORM_MUXSEL     (3<<5)
 #define BT848_IFORM_MUX0       (2<<5)
@@ -71,7 +71,7 @@
 #define BT848_IFORM_AUTO       0
 #define BT848_IFORM_NORM       7
 
-#define BT848_TDEC             0x008  
+#define BT848_TDEC             0x008
 #define BT848_TDEC_DEC_FIELD   (1<<7)
 #define BT848_TDEC_FLDALIGN    (1<<6)
 #define BT848_TDEC_DEC_RAT     (0x1f)
index 3a0320e..6f735d4 100644 (file)
@@ -1,4 +1,6 @@
 /*
+    $Id: btcx-risc.c,v 1.4 2004/11/07 13:17:14 kraxel Exp $
+
     btcx-risc.c
 
     bt848/bt878/cx2388x risc code generator.
@@ -36,7 +38,7 @@ MODULE_AUTHOR("Gerd Knorr");
 MODULE_LICENSE("GPL");
 
 static unsigned int debug = 0;
-MODULE_PARM(debug,"i");
+module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)");
 
 /* ---------------------------------------------------------- */
@@ -187,7 +189,7 @@ btcx_calc_skips(int line, int width, unsigned int *maxy,
 {
        unsigned int clip,skip;
        int end,maxline;
-       
+
        skip=0;
        maxline = 9999;
        for (clip = 0; clip < nclips; clip++) {
@@ -197,7 +199,7 @@ btcx_calc_skips(int line, int width, unsigned int *maxy,
                        continue;
                if (clips[clip].c.left > (signed)width)
                        break;
-               
+
                /* vertical range */
                if (line > clips[clip].c.top+clips[clip].c.height-1)
                        continue;
index 49daaad..41f6039 100644 (file)
@@ -1,4 +1,6 @@
-
+/*
+ * $Id: btcx-risc.h,v 1.2 2004/09/15 16:15:24 kraxel Exp $
+ */
 struct btcx_riscmem {
        unsigned int   size;
        u32            *cpu;
index 585f67d..ef67442 100644 (file)
@@ -1,4 +1,6 @@
 /*
+    $Id: bttv-gpio.c,v 1.6 2004/11/03 09:04:50 kraxel Exp $
+
     bttv-gpio.c  --  gpio sub drivers
 
     sysfs-based sub driver interface for bttv
@@ -22,7 +24,7 @@
     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>
@@ -61,6 +63,7 @@ static void release_sub_device(struct device *dev)
 int bttv_sub_add_device(struct bttv_core *core, char *name)
 {
        struct bttv_sub_device *sub;
+       int err;
 
        sub = kmalloc(sizeof(*sub),GFP_KERNEL);
        if (NULL == sub)
@@ -74,9 +77,13 @@ int bttv_sub_add_device(struct bttv_core *core, char *name)
        snprintf(sub->dev.bus_id,sizeof(sub->dev.bus_id),"%s%d",
                 name, core->nr);
 
+       err = device_register(&sub->dev);
+       if (0 != err) {
+               kfree(sub);
+               return err;
+       }
        printk("bttv%d: add subdevice \"%s\"\n", core->nr, sub->dev.bus_id);
        list_add_tail(&sub->list,&core->subs);
-       device_register(&sub->dev);
        return 0;
 }
 
@@ -127,8 +134,7 @@ int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted)
 {
        sub->drv.bus = &bttv_sub_bus_type;
        snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted);
-       driver_register(&sub->drv);
-       return 0;
+       return driver_register(&sub->drv);
 }
 EXPORT_SYMBOL(bttv_sub_register);
 
index 74da711..935feb7 100644 (file)
@@ -1,4 +1,6 @@
 /*
+    $Id: bttv-if.c,v 1.3 2004/10/13 10:39:00 kraxel Exp $
+
     bttv-if.c  --  old gpio interface to other kernel modules
                    don't use in new code, will go away in 2.7
                   have a look at bttv-gpio.c instead.
@@ -22,7 +24,7 @@
     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>
@@ -80,7 +82,7 @@ int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
        if (card >= bttv_num) {
                return -EINVAL;
        }
-       
+
        btv = &bttvs[card];
        gpio_inout(mask,data);
        if (bttv_gpio)
@@ -91,7 +93,7 @@ int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
 int bttv_read_gpio(unsigned int card, unsigned long *data)
 {
        struct bttv *btv;
-       
+
        if (card >= bttv_num) {
                return -EINVAL;
        }
@@ -102,7 +104,7 @@ int bttv_read_gpio(unsigned int card, unsigned long *data)
                return -ENODEV;
        }
 
-/* prior setting BT848_GPIO_REG_INP is (probably) not needed 
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed
    because we set direct input on init */
        *data = gpio_read();
        return 0;
@@ -111,14 +113,14 @@ int bttv_read_gpio(unsigned int card, unsigned long *data)
 int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
 {
        struct bttv *btv;
-       
+
        if (card >= bttv_num) {
                return -EINVAL;
        }
 
        btv = &bttvs[card];
 
-/* prior setting BT848_GPIO_REG_INP is (probably) not needed 
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed
    because direct input is set on init */
        gpio_bits(mask,data);
        if (bttv_gpio)
index 9f71bef..de2b190 100644 (file)
@@ -1,6 +1,10 @@
-cx88xx-objs    := cx88-cards.o cx88-core.o
-cx8800-objs    := cx88-video.o cx88-tvaudio.o cx88-i2c.o cx88-vbi.o
+cx88xx-objs    := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o
+cx8800-objs    := cx88-video.o cx88-vbi.o
+cx8802-objs    := cx88-mpeg.o
 
-obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o
+obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o
+obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
 
-EXTRA_CFLAGS = -I$(src)/..
+EXTRA_CFLAGS += -I$(src)/..
+EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
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:
+ */
index 8005567..3239c81 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * $Id: cx88-core.c,v 1.15 2004/10/25 11:26:36 kraxel Exp $
+ *
  * device driver for Conexant 2388x based TV cards
  * driver core
  *
@@ -28,6 +30,7 @@
 #include <linux/sound.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 #include <linux/videodev.h>
 
 #include "cx88.h"
@@ -38,42 +41,33 @@ MODULE_LICENSE("GPL");
 
 /* ------------------------------------------------------------------ */
 
-#if 0
-static unsigned int gpio_tracking = 0;
-MODULE_PARM(gpio_tracking,"i");
-MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
+static unsigned int core_debug = 0;
+module_param(core_debug,int,0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
 
-static unsigned int ts_nr = -1;
-MODULE_PARM(ts_nr,"i");
-MODULE_PARM_DESC(ts_nr,"ts device number");
+static unsigned int latency = UNSET;
+module_param(latency,int,0444);
+MODULE_PARM_DESC(latency,"pci latency timer");
 
-static unsigned int vbi_nr = -1;
-MODULE_PARM(vbi_nr,"i");
-MODULE_PARM_DESC(vbi_nr,"vbi device number");
+static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[]  = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
 
-static unsigned int radio_nr = -1;
-MODULE_PARM(radio_nr,"i");
-MODULE_PARM_DESC(radio_nr,"radio device number");
+module_param_array(tuner, int, NULL, 0444);
+module_param_array(card,  int, NULL, 0444);
 
-static unsigned int oss = 0;
-MODULE_PARM(oss,"i");
-MODULE_PARM_DESC(oss,"register oss devices (default: no)");
+MODULE_PARM_DESC(tuner,"tuner type");
+MODULE_PARM_DESC(card,"card type");
 
-static unsigned int dsp_nr = -1;
-MODULE_PARM(dsp_nr,"i");
-MODULE_PARM_DESC(dsp_nr,"oss dsp device number");
+static unsigned int nicam = 0;
+module_param(nicam,int,0644);
+MODULE_PARM_DESC(nicam,"tv audio is nicam");
 
-static unsigned int mixer_nr = -1;
-MODULE_PARM(mixer_nr,"i");
-MODULE_PARM_DESC(mixer_nr,"oss mixer device number");
-#endif
+#define dprintk(level,fmt, arg...)     if (core_debug >= level)        \
+       printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
 
-static unsigned int core_debug = 0;
-MODULE_PARM(core_debug,"i");
-MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
-
-#define dprintk(fmt, arg...)   if (core_debug) \
-       printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
+static unsigned int cx88_devcount;
+static LIST_HEAD(cx88_devlist);
+static DECLARE_MUTEX(devlist);
 
 /* ------------------------------------------------------------------ */
 /* debug help functions                                               */
@@ -129,6 +123,7 @@ void cx88_print_ioctl(char *name, unsigned int cmd)
 }
 
 /* ------------------------------------------------------------------ */
+#define NO_SYNC_LINE (-1U)
 
 static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
                            unsigned int offset, u32 sync_line,
@@ -139,8 +134,9 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
        unsigned int line,todo;
 
        /* sync instruction */
-       *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
-       
+       if (sync_line != NO_SYNC_LINE)
+               *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
        /* scan lines */
        sg = sglist;
        for (line = 0; line < lines; line++) {
@@ -212,6 +208,32 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
+       BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+       return 0;
+}
+
+int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+                        struct scatterlist *sglist, unsigned int bpl,
+                        unsigned int lines)
+{
+       u32 instructions;
+       u32 *rp;
+       int rc;
+
+       /* estimate risc mem: worst case is one write per page border +
+          one write per scan line + syncs + jump (all 2 dwords) */
+       instructions  = (bpl * lines) / PAGE_SIZE + lines;
+       instructions += 3 + 4;
+       if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
+               return rc;
+
+       /* write risc instructions */
+       rp = risc->cpu;
+       rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
+
+       /* save pointer to jmp instruction address */
+       risc->jmp = rp;
+       BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
        return 0;
 }
 
@@ -259,14 +281,16 @@ cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
  *
  * FIFO space allocations:
  *    channel  21    (y video)  - 10.0k
+ *    channel  22    (u video)  -  2.0k
+ *    channel  23    (v video)  -  2.0k
  *    channel  24    (vbi)      -  4.0k
  *    channels 25+26 (audio)    -  0.5k
- *    everything else           -  2.0k
- *    TOTAL                     = 29.0k
+ *    channel  28    (mpeg)     -  4.0k
+ *    TOTAL                     = 25.5k
  *
  * Every channel has 160 bytes control data (64 bytes instruction
  * queue and 6 CDT entries), which is close to 2k total.
- * 
+ *
  * Address layout:
  *    0x0000 - 0x03ff    CMDs / reserved
  *    0x0400 - 0x0bff    instruction queues + CDs
@@ -346,9 +370,21 @@ struct sram_channel cx88_sram_channels[] = {
                .cnt1_reg   = MO_DMA26_CNT1,
                .cnt2_reg   = MO_DMA26_CNT2,
        },
+       [SRAM_CH28] = {
+               .name       = "mpeg",
+               .cmds_start = 0x180200,
+               .ctrl_start = 0x1807C0,
+               .cdt        = 0x1807C0 + 64,
+               .fifo_start = 0x185600,
+               .fifo_size  = 0x001000,
+               .ptr1_reg   = MO_DMA28_PTR1,
+               .ptr2_reg   = MO_DMA28_PTR2,
+               .cnt1_reg   = MO_DMA28_CNT1,
+               .cnt2_reg   = MO_DMA28_CNT2,
+       },
 };
 
-int cx88_sram_channel_setup(struct cx8800_dev *dev,
+int cx88_sram_channel_setup(struct cx88_core *core,
                            struct sram_channel *ch,
                            unsigned int bpl, u32 risc)
 {
@@ -378,10 +414,10 @@ int cx88_sram_channel_setup(struct cx8800_dev *dev,
        /* fill registers */
        cx_write(ch->ptr1_reg, ch->fifo_start);
        cx_write(ch->ptr2_reg, cdt);
-       cx_write(ch->cnt1_reg, bpl >> 3);
+       cx_write(ch->cnt1_reg, (bpl >> 3) -1);
        cx_write(ch->cnt2_reg, (lines*16) >> 3);
 
-       dprintk("sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
+       dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
        return 0;
 }
 
@@ -426,25 +462,25 @@ int cx88_risc_decode(u32 risc)
        return incr[risc >> 28] ? incr[risc >> 28] : 1;
 }
 
-void cx88_risc_disasm(struct cx8800_dev *dev,
+void cx88_risc_disasm(struct cx88_core *core,
                      struct btcx_riscmem *risc)
 {
        unsigned int i,j,n;
-       
+
        printk("%s: risc disasm: %p [dma=0x%08lx]\n",
-              dev->name, risc->cpu, (unsigned long)risc->dma);
+              core->name, risc->cpu, (unsigned long)risc->dma);
        for (i = 0; i < (risc->size >> 2); i += n) {
-               printk("%s:   %04d: ", dev->name, i);
+               printk("%s:   %04d: ", core->name, i);
                n = cx88_risc_decode(risc->cpu[i]);
                for (j = 1; j < n; j++)
                        printk("%s:   %04d: 0x%08x [ arg #%d ]\n",
-                              dev->name, i+j, risc->cpu[i+j], j);
+                              core->name, i+j, risc->cpu[i+j], j);
                if (risc->cpu[i] == RISC_JUMP)
                        break;
        }
 }
 
-void cx88_sram_channel_dump(struct cx8800_dev *dev,
+void cx88_sram_channel_dump(struct cx88_core *core,
                            struct sram_channel *ch)
 {
        static char *name[] = {
@@ -463,54 +499,63 @@ void cx88_sram_channel_dump(struct cx8800_dev *dev,
        u32 risc;
        unsigned int i,j,n;
 
-       printk("%s: %s - dma channel status dump\n",dev->name,ch->name);
+       printk("%s: %s - dma channel status dump\n",
+              core->name,ch->name);
        for (i = 0; i < ARRAY_SIZE(name); i++)
                printk("%s:   cmds: %-12s: 0x%08x\n",
-                      dev->name,name[i],
+                      core->name,name[i],
                       cx_read(ch->cmds_start + 4*i));
        for (i = 0; i < 4; i++) {
                risc = cx_read(ch->cmds_start + 4 * (i+11));
-               printk("%s:   risc%d: ", dev->name, i);
+               printk("%s:   risc%d: ", core->name, i);
                cx88_risc_decode(risc);
        }
        for (i = 0; i < 16; i += n) {
                risc = cx_read(ch->ctrl_start + 4 * i);
-               printk("%s:   iq %x: ", dev->name, i);
+               printk("%s:   iq %x: ", core->name, i);
                n = cx88_risc_decode(risc);
                for (j = 1; j < n; j++) {
                        risc = cx_read(ch->ctrl_start + 4 * (i+j));
                        printk("%s:   iq %x: 0x%08x [ arg #%d ]\n",
-                              dev->name, i+j, risc, j);
+                              core->name, i+j, risc, j);
                }
        }
 
        printk("%s: fifo: 0x%08x -> 0x%x\n",
-              dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
+              core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
        printk("%s: ctrl: 0x%08x -> 0x%x\n",
-              dev->name, ch->ctrl_start, ch->ctrl_start+6*16);
+              core->name, ch->ctrl_start, ch->ctrl_start+6*16);
        printk("%s:   ptr1_reg: 0x%08x\n",
-              dev->name,cx_read(ch->ptr1_reg));
+              core->name,cx_read(ch->ptr1_reg));
        printk("%s:   ptr2_reg: 0x%08x\n",
-              dev->name,cx_read(ch->ptr2_reg));
+              core->name,cx_read(ch->ptr2_reg));
        printk("%s:   cnt1_reg: 0x%08x\n",
-              dev->name,cx_read(ch->cnt1_reg));
+              core->name,cx_read(ch->cnt1_reg));
        printk("%s:   cnt2_reg: 0x%08x\n",
-              dev->name,cx_read(ch->cnt2_reg));
+              core->name,cx_read(ch->cnt2_reg));
 }
 
 char *cx88_pci_irqs[32] = {
-       "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1", 
+       "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
        "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
        "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
        "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
 };
 char *cx88_vid_irqs[32] = {
-       "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", 
+       "y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
        "y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
        "y_oflow",  "u_oflow",  "v_oflow",  "vbi_oflow",
        "y_sync",   "u_sync",   "v_sync",   "vbi_sync",
        "opc_err",  "par_err",  "rip_err",  "pci_abort",
 };
+char *cx88_mpeg_irqs[32] = {
+       "ts_risci1", NULL, NULL, NULL,
+       "ts_risci2", NULL, NULL, NULL,
+       "ts_oflow",  NULL, NULL, NULL,
+       "ts_sync",   NULL, NULL, NULL,
+       "opc_err", "par_err", "rip_err", "pci_abort",
+       "ts_err?",
+};
 
 void cx88_print_irqbits(char *name, char *tag, char **strings,
                        u32 bits, u32 mask)
@@ -521,7 +566,10 @@ void cx88_print_irqbits(char *name, char *tag, char **strings,
        for (i = 0; i < 32; i++) {
                if (!(bits & (1 << i)))
                        continue;
-               printk(" %s",strings[i]);
+               if (strings[i])
+                       printk(" %s", strings[i]);
+               else
+                       printk(" %d", i);
                if (!(mask & (1 << i)))
                        continue;
                printk("*");
@@ -531,14 +579,429 @@ void cx88_print_irqbits(char *name, char *tag, char **strings,
 
 /* ------------------------------------------------------------------ */
 
-int cx88_pci_quirks(char *name, struct pci_dev *pci, unsigned int *latency)
+void cx88_irq(struct cx88_core *core, u32 status, u32 mask)
 {
-       u8 ctrl = 0;
-       u8 value;
+       cx88_print_irqbits(core->name, "irq pci",
+                          cx88_pci_irqs, status, mask);
+}
+
+void cx88_wakeup(struct cx88_core *core,
+                struct cx88_dmaqueue *q, u32 count)
+{
+       struct cx88_buffer *buf;
+       int bc;
+
+       for (bc = 0;; bc++) {
+               if (list_empty(&q->active))
+                       break;
+               buf = list_entry(q->active.next,
+                                struct cx88_buffer, vb.queue);
+#if 0
+               if (buf->count > count)
+                       break;
+#else
+               /* count comes from the hw and is is 16bit wide --
+                * this trick handles wrap-arounds correctly for
+                * up to 32767 buffers in flight... */
+               if ((s16) (count - buf->count) < 0)
+                       break;
+#endif
+               do_gettimeofday(&buf->vb.ts);
+               dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
+                       count, buf->count);
+               buf->vb.state = STATE_DONE;
+               list_del(&buf->vb.queue);
+               wake_up(&buf->vb.done);
+       }
+       if (list_empty(&q->active)) {
+               del_timer(&q->timeout);
+       } else {
+               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+       }
+       if (bc != 1)
+               printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
+}
+
+void cx88_shutdown(struct cx88_core *core)
+{
+       /* disable RISC controller + IRQs */
+       cx_write(MO_DEV_CNTRL2, 0);
+
+       /* stop dma transfers */
+       cx_write(MO_VID_DMACNTRL, 0x0);
+       cx_write(MO_AUD_DMACNTRL, 0x0);
+       cx_write(MO_TS_DMACNTRL, 0x0);
+       cx_write(MO_VIP_DMACNTRL, 0x0);
+       cx_write(MO_GPHST_DMACNTRL, 0x0);
+
+       /* stop interrupts */
+       cx_write(MO_PCI_INTMSK, 0x0);
+       cx_write(MO_VID_INTMSK, 0x0);
+       cx_write(MO_AUD_INTMSK, 0x0);
+       cx_write(MO_TS_INTMSK, 0x0);
+       cx_write(MO_VIP_INTMSK, 0x0);
+       cx_write(MO_GPHST_INTMSK, 0x0);
 
-       if (0 == pci_pci_problems)
+       /* stop capturing */
+       cx_write(VID_CAPTURE_CONTROL, 0);
+}
+
+int cx88_reset(struct cx88_core *core)
+{
+       dprintk(1,"%s\n",__FUNCTION__);
+       cx88_shutdown(core);
+
+       /* clear irq status */
+       cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
+       cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
+       cx_write(MO_INT1_STAT,   0xFFFFFFFF); // Clear RISC int
+
+       /* wait a bit */
+       msleep(100);
+
+       /* init sram */
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
+
+       /* misc init ... */
+       cx_write(MO_INPUT_FORMAT, ((1 << 13) |   // agc enable
+                                  (1 << 12) |   // agc gain
+                                  (1 << 11) |   // adaptibe agc
+                                  (0 << 10) |   // chroma agc
+                                  (0 <<  9) |   // ckillen
+                                  (7)));
+
+       /* setup image format */
+       cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
+
+       /* setup FIFO Threshholds */
+       cx_write(MO_PDMA_STHRSH,   0x0807);
+       cx_write(MO_PDMA_DTHRSH,   0x0807);
+
+       /* fixes flashing of image */
+       cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
+       cx_write(MO_AGC_BACK_VBI,  0x00E00555);
+
+       cx_write(MO_VID_INTSTAT,   0xFFFFFFFF); // Clear PIV int
+       cx_write(MO_PCI_INTSTAT,   0xFFFFFFFF); // Clear PCI int
+       cx_write(MO_INT1_STAT,     0xFFFFFFFF); // Clear RISC int
+
+       /* Reset on-board parts */
+       cx_write(MO_SRST_IO, 0);
+       msleep(10);
+       cx_write(MO_SRST_IO, 1);
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
+{
+       return (norm->id & V4L2_STD_625_50) ? 922 : 754;
+}
+
+static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
+{
+       return (norm->id & V4L2_STD_625_50) ? 186 : 135;
+}
+
+static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
+{
+       return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
+}
+
+static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
+{
+       static const unsigned int ntsc = 28636360;
+       static const unsigned int pal  = 35468950;
+
+       return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
+}
+
+static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
+{
+       return (norm->id & V4L2_STD_625_50)
+               ? HLNotchFilter135PAL
+               : HLNotchFilter135NTSC;
+}
+
+static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
+{
+       return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
+}
+
+static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
+{
+       return (norm->id & V4L2_STD_625_50) ? 511 : 288;
+}
+
+int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
+                  enum v4l2_field field)
+{
+       unsigned int swidth  = norm_swidth(core->tvnorm);
+       unsigned int sheight = norm_maxh(core->tvnorm);
+       u32 value;
+
+       dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
+               V4L2_FIELD_HAS_TOP(field)    ? "T" : "",
+               V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+               core->tvnorm->name);
+       if (!V4L2_FIELD_HAS_BOTH(field))
+               height *= 2;
+
+       // recalc H delay and scale registers
+       value = (width * norm_hdelay(core->tvnorm)) / swidth;
+       value &= 0x3fe;
+       cx_write(MO_HDELAY_EVEN,  value);
+       cx_write(MO_HDELAY_ODD,   value);
+       dprintk(1,"set_scale: hdelay  0x%04x\n", value);
+
+       value = (swidth * 4096 / width) - 4096;
+       cx_write(MO_HSCALE_EVEN,  value);
+       cx_write(MO_HSCALE_ODD,   value);
+       dprintk(1,"set_scale: hscale  0x%04x\n", value);
+
+       cx_write(MO_HACTIVE_EVEN, width);
+       cx_write(MO_HACTIVE_ODD,  width);
+       dprintk(1,"set_scale: hactive 0x%04x\n", width);
+
+       // recalc V scale Register (delay is constant)
+       cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
+       cx_write(MO_VDELAY_ODD,  norm_vdelay(core->tvnorm));
+       dprintk(1,"set_scale: vdelay  0x%04x\n", norm_vdelay(core->tvnorm));
+
+       value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
+       cx_write(MO_VSCALE_EVEN,  value);
+       cx_write(MO_VSCALE_ODD,   value);
+       dprintk(1,"set_scale: vscale  0x%04x\n", value);
+
+       cx_write(MO_VACTIVE_EVEN, sheight);
+       cx_write(MO_VACTIVE_ODD,  sheight);
+       dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
+
+       // setup filters
+       value = 0;
+       value |= (1 << 19);        // CFILT (default)
+       if (core->tvnorm->id & V4L2_STD_SECAM) {
+               value |= (1 << 15);
+               value |= (1 << 16);
+       }
+       if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
+               value |= (1 << 13) | (1 << 5);
+       if (V4L2_FIELD_INTERLACED == field)
+               value |= (1 << 3); // VINT (interlaced vertical scaling)
+       if (width < 385)
+               value |= (1 << 0); // 3-tap interpolation
+       if (width < 193)
+               value |= (1 << 1); // 5-tap interpolation
+
+       cx_write(MO_FILTER_EVEN,  value);
+       cx_write(MO_FILTER_ODD,   value);
+       dprintk(1,"set_scale: filter  0x%04x\n", value);
+
+       return 0;
+}
+
+static const u32 xtal = 28636363;
+
+static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
+{
+       static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
+       u64 pll;
+       u32 reg;
+       int i;
+
+       if (prescale < 2)
+               prescale = 2;
+       if (prescale > 5)
+               prescale = 5;
+
+       pll = ofreq * 8 * prescale * (u64)(1 << 20);
+       do_div(pll,xtal);
+       reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
+       if (((reg >> 20) & 0x3f) < 14) {
+               printk("%s/0: pll out of range\n",core->name);
+               return -1;
+       }
+
+       dprintk(1,"set_pll:    MO_PLL_REG       0x%08x [old=0x%08x,freq=%d]\n",
+               reg, cx_read(MO_PLL_REG), ofreq);
+       cx_write(MO_PLL_REG, reg);
+       for (i = 0; i < 100; i++) {
+               reg = cx_read(MO_DEVICE_STATUS);
+               if (reg & (1<<2)) {
+                       dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
+                               prescale,ofreq);
+                       return 0;
+               }
+               dprintk(1,"pll not locked yet, waiting ...\n");
+               msleep(10);
+       }
+       dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
+       return -1;
+}
+
+static int set_tvaudio(struct cx88_core *core)
+{
+       struct cx88_tvnorm *norm = core->tvnorm;
+
+       if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
+               return 0;
+
+       if (V4L2_STD_PAL_BG & norm->id) {
+               core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
+
+       } else if (V4L2_STD_PAL_DK & norm->id) {
+               core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
+
+       } else if (V4L2_STD_PAL_I & norm->id) {
+               core->tvaudio = WW_NICAM_I;
+
+       } else if (V4L2_STD_SECAM_L & norm->id) {
+               core->tvaudio = WW_SYSTEM_L_AM;
+
+       } else if (V4L2_STD_SECAM_DK & norm->id) {
+               core->tvaudio = WW_A2_DK;
+
+       } else if ((V4L2_STD_NTSC_M & norm->id) ||
+                  (V4L2_STD_PAL_M  & norm->id)) {
+               core->tvaudio = WW_BTSC;
+
+       } else if (V4L2_STD_NTSC_M_JP & norm->id) {
+               core->tvaudio = WW_EIAJ;
+
+       } else {
+               printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
+                      core->name, norm->name);
+               core->tvaudio = 0;
                return 0;
+       }
+
+       cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
+       cx88_set_tvaudio(core);
+       // cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
+
+       cx_write(MO_AUDD_LNGTH, 128/8);  /* fifo size */
+       cx_write(MO_AUDR_LNGTH, 128/8);  /* fifo size */
+       cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */
+       return 0;
+}
+
+int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
+{
+       u32 fsc8;
+       u32 adc_clock;
+       u32 vdec_clock;
+       u32 step_db,step_dr;
+       u64 tmp64;
+       u32 bdelay,agcdelay,htotal;
+
+       core->tvnorm = norm;
+       fsc8       = norm_fsc8(norm);
+       adc_clock  = xtal;
+       vdec_clock = fsc8;
+       step_db    = fsc8;
+       step_dr    = fsc8;
+
+       if (norm->id & V4L2_STD_SECAM) {
+               step_db = 4250000 * 8;
+               step_dr = 4406250 * 8;
+       }
+
+       dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
+               norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
+       set_pll(core,2,vdec_clock);
 
+       dprintk(1,"set_tvnorm: MO_INPUT_FORMAT  0x%08x [old=0x%08x]\n",
+               norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
+       cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
+
+#if 1
+       // FIXME: as-is from DScaler
+       dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
+               norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
+       cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
+#endif
+
+       // MO_SCONV_REG = adc clock / video dec clock * 2^17
+       tmp64  = adc_clock * (u64)(1 << 17);
+       do_div(tmp64, vdec_clock);
+       dprintk(1,"set_tvnorm: MO_SCONV_REG     0x%08x [old=0x%08x]\n",
+               (u32)tmp64, cx_read(MO_SCONV_REG));
+       cx_write(MO_SCONV_REG, (u32)tmp64);
+
+       // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
+       tmp64  = step_db * (u64)(1 << 22);
+       do_div(tmp64, vdec_clock);
+       dprintk(1,"set_tvnorm: MO_SUB_STEP      0x%08x [old=0x%08x]\n",
+               (u32)tmp64, cx_read(MO_SUB_STEP));
+       cx_write(MO_SUB_STEP, (u32)tmp64);
+
+       // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
+       tmp64  = step_dr * (u64)(1 << 22);
+       do_div(tmp64, vdec_clock);
+       dprintk(1,"set_tvnorm: MO_SUB_STEP_DR   0x%08x [old=0x%08x]\n",
+               (u32)tmp64, cx_read(MO_SUB_STEP_DR));
+       cx_write(MO_SUB_STEP_DR, (u32)tmp64);
+
+       // bdelay + agcdelay
+       bdelay   = vdec_clock * 65 / 20000000 + 21;
+       agcdelay = vdec_clock * 68 / 20000000 + 15;
+       dprintk(1,"set_tvnorm: MO_AGC_BURST     0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
+               (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
+       cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
+
+       // htotal
+       tmp64 = norm_htotal(norm) * (u64)vdec_clock;
+       do_div(tmp64, fsc8);
+       htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
+       dprintk(1,"set_tvnorm: MO_HTOTAL        0x%08x [old=0x%08x,htotal=%d]\n",
+               htotal, cx_read(MO_HTOTAL), (u32)tmp64);
+       cx_write(MO_HTOTAL, htotal);
+
+       // vbi stuff
+       cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm)   << 11) | */
+                                norm_vbipack(norm)));
+
+       // audio
+       set_tvaudio(core);
+
+       // tell i2c chips
+#ifdef V4L2_I2C_CLIENTS
+       cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
+#else
+       {
+               struct video_channel c;
+               memset(&c,0,sizeof(c));
+               c.channel = core->input;
+               c.norm = VIDEO_MODE_PAL;
+               if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
+                       c.norm = VIDEO_MODE_NTSC;
+               if (norm->id & V4L2_STD_SECAM)
+                       c.norm = VIDEO_MODE_SECAM;
+               cx88_call_i2c_clients(core,VIDIOCSCHAN,&c);
+       }
+#endif
+
+       // done
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int cx88_pci_quirks(char *name, struct pci_dev *pci)
+{
+       unsigned int lat = UNSET;
+       u8 ctrl = 0;
+       u8 value;
+
+       /* check pci quirks */
        if (pci_pci_problems & PCIPCI_TRITON) {
                printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
                       name);
@@ -563,25 +1026,174 @@ int cx88_pci_quirks(char *name, struct pci_dev *pci, unsigned int *latency)
        if (pci_pci_problems & PCIPCI_ALIMAGIK) {
                printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
                       name);
-               *latency = 0x0A;
+               lat = 0x0A;
        }
 #endif
+
+       /* check insmod options */
+       if (UNSET != latency)
+               lat = latency;
+
+       /* apply stuff */
        if (ctrl) {
                pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
                value |= ctrl;
                pci_write_config_byte(pci, CX88X_DEVCTRL, value);
        }
+       if (UNSET != lat) {
+               printk(KERN_INFO "%s: setting pci latency timer to %d\n",
+                      name, latency);
+               pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
+       }
        return 0;
 }
 
 /* ------------------------------------------------------------------ */
 
+struct video_device *cx88_vdev_init(struct cx88_core *core,
+                                   struct pci_dev *pci,
+                                   struct video_device *template,
+                                   char *type)
+{
+       struct video_device *vfd;
+
+       vfd = video_device_alloc();
+       if (NULL == vfd)
+               return NULL;
+       *vfd = *template;
+       vfd->minor   = -1;
+       vfd->dev     = &pci->dev;
+       vfd->release = video_device_release;
+       snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+                core->name, type, cx88_boards[core->board].name);
+       return vfd;
+}
+
+static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
+{
+       if (request_mem_region(pci_resource_start(pci,0),
+                              pci_resource_len(pci,0),
+                              core->name))
+               return 0;
+       printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
+              core->name,pci_resource_start(pci,0));
+       return -EBUSY;
+}
+
+struct cx88_core* cx88_core_get(struct pci_dev *pci)
+{
+       struct cx88_core *core;
+       struct list_head *item;
+       int i;
+
+       down(&devlist);
+       list_for_each(item,&cx88_devlist) {
+               core = list_entry(item, struct cx88_core, devlist);
+               if (pci->bus->number != core->pci_bus)
+                       continue;
+               if (PCI_SLOT(pci->devfn) != core->pci_slot)
+                       continue;
+
+               if (0 != get_ressources(core,pci))
+                       goto fail_unlock;
+               atomic_inc(&core->refcount);
+               up(&devlist);
+               return core;
+       }
+       core = kmalloc(sizeof(*core),GFP_KERNEL);
+       if (NULL == core)
+               goto fail_unlock;
+
+       memset(core,0,sizeof(*core));
+       core->pci_bus  = pci->bus->number;
+       core->pci_slot = PCI_SLOT(pci->devfn);
+       atomic_inc(&core->refcount);
+
+       core->nr = cx88_devcount++;
+       sprintf(core->name,"cx88[%d]",core->nr);
+       if (0 != get_ressources(core,pci)) {
+               cx88_devcount--;
+               goto fail_free;
+       }
+       list_add_tail(&core->devlist,&cx88_devlist);
+
+       /* PCI stuff */
+       cx88_pci_quirks(core->name, pci);
+       core->lmmio = ioremap(pci_resource_start(pci,0),
+                             pci_resource_len(pci,0));
+       core->bmmio = (u8 __iomem *)core->lmmio;
+
+       /* board config */
+       core->board = UNSET;
+       if (card[core->nr] < cx88_bcount)
+               core->board = card[core->nr];
+       for (i = 0; UNSET == core->board  &&  i < cx88_idcount; i++)
+               if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
+                   pci->subsystem_device == cx88_subids[i].subdevice)
+                       core->board = cx88_subids[i].card;
+       if (UNSET == core->board) {
+               core->board = CX88_BOARD_UNKNOWN;
+               cx88_card_list(core,pci);
+       }
+        printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+              core->name,pci->subsystem_vendor,
+              pci->subsystem_device,cx88_boards[core->board].name,
+              core->board, card[core->nr] == core->board ?
+              "insmod option" : "autodetected");
+
+       core->tuner_type = tuner[core->nr];
+       if (UNSET == core->tuner_type)
+               core->tuner_type = cx88_boards[core->board].tuner_type;
+       core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
+
+       /* init hardware */
+       cx88_reset(core);
+       cx88_i2c_init(core,pci);
+       cx88_card_setup(core);
+
+       up(&devlist);
+       return core;
+
+fail_free:
+       kfree(core);
+fail_unlock:
+       up(&devlist);
+       return NULL;
+}
+
+void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
+{
+       release_mem_region(pci_resource_start(pci,0),
+                          pci_resource_len(pci,0));
+
+       if (!atomic_dec_and_test(&core->refcount))
+               return;
+
+       down(&devlist);
+       if (0 == core->i2c_rc)
+               i2c_bit_del_bus(&core->i2c_adap);
+       list_del(&core->devlist);
+       iounmap(core->lmmio);
+       cx88_devcount--;
+       up(&devlist);
+       kfree(core);
+}
+
+/* ------------------------------------------------------------------ */
+
 EXPORT_SYMBOL(cx88_print_ioctl);
 EXPORT_SYMBOL(cx88_pci_irqs);
 EXPORT_SYMBOL(cx88_vid_irqs);
+EXPORT_SYMBOL(cx88_mpeg_irqs);
 EXPORT_SYMBOL(cx88_print_irqbits);
 
+EXPORT_SYMBOL(cx88_irq);
+EXPORT_SYMBOL(cx88_wakeup);
+EXPORT_SYMBOL(cx88_reset);
+EXPORT_SYMBOL(cx88_shutdown);
+
 EXPORT_SYMBOL(cx88_risc_buffer);
+EXPORT_SYMBOL(cx88_risc_databuffer);
 EXPORT_SYMBOL(cx88_risc_stopper);
 EXPORT_SYMBOL(cx88_free_buffer);
 
@@ -591,7 +1203,12 @@ EXPORT_SYMBOL(cx88_sram_channels);
 EXPORT_SYMBOL(cx88_sram_channel_setup);
 EXPORT_SYMBOL(cx88_sram_channel_dump);
 
-EXPORT_SYMBOL(cx88_pci_quirks);
+EXPORT_SYMBOL(cx88_set_tvnorm);
+EXPORT_SYMBOL(cx88_set_scale);
+
+EXPORT_SYMBOL(cx88_vdev_init);
+EXPORT_SYMBOL(cx88_core_get);
+EXPORT_SYMBOL(cx88_core_put);
 
 /*
  * Local variables:
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:
+ */
index 9673133..d70a954 100644 (file)
@@ -8,7 +8,29 @@ struct msp_dfpreg {
     int value;
 };
 
+struct msp_matrix {
+  int input;
+  int output;
+};
+
 #define MSP_SET_DFPREG     _IOW('m',15,struct msp_dfpreg)
 #define MSP_GET_DFPREG     _IOW('m',16,struct msp_dfpreg)
 
+/* ioctl for MSP_SET_MATRIX will have to be registered */
+#define MSP_SET_MATRIX     _IOW('m',17,struct msp_matrix)
+
+#define SCART_MASK    0
+#define SCART_IN1     1
+#define SCART_IN2     2
+#define SCART_IN1_DA  3
+#define SCART_IN2_DA  4
+#define SCART_IN3     5
+#define SCART_IN4     6
+#define SCART_MONO    7
+#define SCART_MUTE    8
+
+#define SCART_DSP_IN  0
+#define SCART1_OUT    1
+#define SCART2_OUT    2
+
 #endif /* MSP3400_H */
index d88956a..67f2fc4 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include "ovcamchip_priv.h"
 
 #define DRIVER_VERSION "v2.27 for Linux 2.6"
@@ -128,8 +129,7 @@ static int init_camchip(struct i2c_client *c)
        ov_write(c, 0x12, 0x80);
 
        /* Wait for it to initialize */
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(1 + 150 * HZ / 1000);
+       msleep(150);
 
        for (i = 0, success = 0; i < I2C_DETECT_RETRIES && !success; i++) {
                if (ov_read(c, GENERIC_REG_ID_HIGH, &high) >= 0) {
@@ -145,8 +145,7 @@ static int init_camchip(struct i2c_client *c)
                ov_write(c, 0x12, 0x80);
 
                /* Wait for it to initialize */
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1 + 150 * HZ / 1000);
+               msleep(150);
 
                /* Dummy read to sync I2C */
                ov_read(c, 0x00, &low);
index 95f8938..25028ce 100644 (file)
@@ -3,6 +3,8 @@ saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o    \
                saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o    \
                saa7134-vbi.o saa7134-video.o saa7134-input.o
 
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
-EXTRA_CFLAGS = -I$(src)/..
+EXTRA_CFLAGS += -I$(src)/..
+EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
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:
+ */
index c39ea87..87734f2 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * $Id: saa7134-reg.h,v 1.2 2004/09/15 16:15:24 kraxel Exp $
+ *
  * philips saa7134 registers
  */
 
index 01451b3..5707e90 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * $Id: saa7134-vbi.c,v 1.5 2004/11/07 13:17:15 kraxel Exp $
+ *
  * device driver for philips saa7134 based TV cards
  * video4linux video interface
  *
 /* ------------------------------------------------------------------ */
 
 static unsigned int vbi_debug  = 0;
-MODULE_PARM(vbi_debug,"i");
+module_param(vbi_debug, int, 0644);
 MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
 
 static unsigned int vbibufs = 4;
-MODULE_PARM(vbibufs,"i");
+module_param(vbibufs, int, 0444);
 MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
 
 #define dprintk(fmt, arg...)   if (vbi_debug) \
@@ -51,7 +53,7 @@ static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf,
                      int task)
 {
        struct saa7134_tvnorm *norm = dev->tvnorm;
-       
+
        /* setup video scaler */
        saa_writeb(SAA7134_VBI_H_START1(task), norm->h_start     &  0xff);
        saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start     >> 8);
@@ -113,12 +115,13 @@ static int buffer_activate(struct saa7134_dev *dev,
        return 0;
 }
 
-static int buffer_prepare(struct file *file, struct videobuf_buffer *vb,
+static int buffer_prepare(struct videobuf_queue *q,
+                         struct videobuf_buffer *vb,
                          enum v4l2_field field)
 {
-       struct saa7134_fh *fh   = file->private_data;
+       struct saa7134_fh *fh   = q->priv_data;
        struct saa7134_dev *dev = fh->dev;
-       struct saa7134_buf *buf = (struct saa7134_buf *)vb;
+       struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
        struct saa7134_tvnorm *norm = dev->tvnorm;
        unsigned int lines, llength, size;
        int err;
@@ -167,12 +170,12 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb,
 }
 
 static int
-buffer_setup(struct file *file, unsigned int *count, unsigned int *size)
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
 {
-       struct saa7134_fh *fh   = file->private_data;
+       struct saa7134_fh *fh   = q->priv_data;
        struct saa7134_dev *dev = fh->dev;
        int llength,lines;
-       
+
        lines   = dev->tvnorm->vbi_v_stop - dev->tvnorm->vbi_v_start +1;
 #if 1
        llength = VBI_LINE_LENGTH;
@@ -188,21 +191,21 @@ buffer_setup(struct file *file, unsigned int *count, unsigned int *size)
        return 0;
 }
 
-static void buffer_queue(struct file *file, struct videobuf_buffer *vb)
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_fh *fh = q->priv_data;
        struct saa7134_dev *dev = fh->dev;
-       struct saa7134_buf *buf = (struct saa7134_buf *)vb;
-       
+       struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
        saa7134_buffer_queue(dev,&dev->vbi_q,buf);
 }
 
-static void buffer_release(struct file *file, struct videobuf_buffer *vb)
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_fh *fh   = file->private_data;
+       struct saa7134_fh *fh   = q->priv_data;
        struct saa7134_dev *dev = fh->dev;
-       struct saa7134_buf *buf = (struct saa7134_buf *)vb;
-       
+       struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
        saa7134_dma_free(dev,buf);
 }
 
index e131ca2..f305ec8 100644 (file)
@@ -78,7 +78,7 @@ struct saa7146
        unsigned char boardcfg[64];     /* 64 bytes of config from eeprom */
        unsigned long saa7146_adr;   /* bus address of IO mem from PCI BIOS */
        struct saa7146_window win;
-       unsigned char *saa7146_mem; /* pointer to mapped IO memory */
+       unsigned char __iomem *saa7146_mem; /* pointer to mapped IO memory */
        struct device_open open_data[MAX_OPENS];
 #define MAX_MARKS 16
        /* for a/v sync */
@@ -95,10 +95,10 @@ struct saa7146
 #endif
 
 #ifdef _ALPHA_SAA7146
-#define saawrite(dat,adr)    writel((dat),(char *) (saa->saa7146_adr+(adr)))
+#define saawrite(dat,adr)    writel((dat), saa->saa7146_adr+(adr))
 #define saaread(adr)         readl(saa->saa7146_adr+(adr))
 #else
-#define saawrite(dat,adr)    writel((dat), (char *) (saa->saa7146_mem+(adr)))
+#define saawrite(dat,adr)    writel((dat), saa->saa7146_mem+(adr))
 #define saaread(adr)         readl(saa->saa7146_mem+(adr))
 #endif
 
index 6f079fd..b5e0cf3 100644 (file)
@@ -36,7 +36,7 @@
 /*
  * Video4linux 1/2 integration by Justin Schoeman
  * <justin@suntiger.ee.up.ac.za>
- * 2.4 PROCFS support ported from 2.4 kernels by 
+ * 2.4 PROCFS support ported from 2.4 kernels by
  *  Iñaki García Etxebarria <garetxe@euskalnet.net>
  * Makefile fix by "W. Michael Petullo" <mike@flyn.org>
  * 2.4 devfs support ported from 2.4 kernels by
@@ -84,17 +84,20 @@ MODULE_LICENSE("GPL");
  *  Video Standard Operations (contributed by Michael Schimek)
  */
 
-/* This is the recommended method to deal with the framerate fields. More 
+#if 0 /* seems to have no users */
+/* This is the recommended method to deal with the framerate fields. More
    sophisticated drivers will access the fields directly. */
 unsigned int
 v4l2_video_std_fps(struct v4l2_standard *vs)
-{ 
+{
        if (vs->frameperiod.numerator > 0)
-               return (((vs->frameperiod.denominator << 8) / 
-                        vs->frameperiod.numerator) + 
+               return (((vs->frameperiod.denominator << 8) /
+                        vs->frameperiod.numerator) +
                        (1 << 7)) / (1 << 8);
        return 0;
 }
+EXPORT_SYMBOL(v4l2_video_std_fps);
+#endif
 
 /* Fill in the fields of a v4l2_standard structure according to the
    'id' and 'transmission' parameters.  Returns negative on error.  */
@@ -132,7 +135,7 @@ int v4l2_prio_init(struct v4l2_prio_state *global)
        memset(global,0,sizeof(*global));
        return 0;
 }
-       
+
 int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
                     enum v4l2_priority new)
 {
@@ -259,7 +262,6 @@ char *v4l2_ioctl_names[256] = {
 
 /* ----------------------------------------------------------------- */
 
-EXPORT_SYMBOL(v4l2_video_std_fps);
 EXPORT_SYMBOL(v4l2_video_std_construct);
 
 EXPORT_SYMBOL(v4l2_prio_init);
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:
+ */
index 8656d58..9fe6ad3 100644 (file)
@@ -407,7 +407,7 @@ struct zoran {
        struct pci_dev *pci_dev;        /* PCI device */
        unsigned char revision; /* revision of zr36057 */
        unsigned int zr36057_adr;       /* bus address of IO mem returned by PCI BIOS */
-       unsigned char *zr36057_mem;     /* pointer to mapped IO memory */
+       unsigned char __iomem *zr36057_mem;/* pointer to mapped IO memory */
 
        spinlock_t spinlock;    /* Spinlock */
 
@@ -499,10 +499,10 @@ struct zoran {
   of _ALPHA_BUZ in the Makefile.*/
 
 #ifdef _ALPHA_BUZ
-#define btwrite(dat,adr)    writel((dat),(char *) (zr->zr36057_adr+(adr)))
+#define btwrite(dat,adr)    writel((dat), zr->zr36057_adr+(adr))
 #define btread(adr)         readl(zr->zr36057_adr+(adr))
 #else
-#define btwrite(dat,adr)    writel((dat), (char *) (zr->zr36057_mem+(adr)))
+#define btwrite(dat,adr)    writel((dat), zr->zr36057_mem+(adr))
 #define btread(adr)         readl(zr->zr36057_mem+(adr))
 #endif
 
index 7227a8a..2a5d478 100644 (file)
@@ -4,40 +4,14 @@
 #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_fail_status(u8 req_status, u32 * msg);
+static 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.
@@ -54,7 +28,7 @@ void i2o_report_status(const char *severity, const char *str,
        if (cmd == I2O_CMD_UTIL_EVT_REGISTER)
                return;         // No status in this reply
 
-       printk("%s%s: ", severity, str);
+       printk(KERN_DEBUG "%s%s: ", severity, str);
 
        if (cmd < 0x1F)         // Utility cmd
                i2o_report_util_cmd(cmd);
@@ -62,7 +36,7 @@ void i2o_report_status(const char *severity, const char *str,
        else if (cmd >= 0xA0 && cmd <= 0xEF)    // Executive cmd
                i2o_report_exec_cmd(cmd);
        else
-               printk("Cmd = %0#2x, ", cmd);   // Other cmds
+               printk(KERN_DEBUG "Cmd = %0#2x, ", cmd);        // Other cmds
 
        if (msg[0] & MSG_FAIL) {
                i2o_report_fail_status(req_status, msg);
@@ -74,7 +48,8 @@ void i2o_report_status(const char *severity, const char *str,
        if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
                i2o_report_common_dsc(detailed_status);
        else
-               printk(" / DetailedStatus = %0#4x.\n", detailed_status);
+               printk(KERN_DEBUG " / DetailedStatus = %0#4x.\n",
+                      detailed_status);
 }
 
 /* Used to dump a message to syslog during debugging */
@@ -90,71 +65,12 @@ void i2o_dump_message(struct i2o_message *m)
 #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 void i2o_report_fail_status(u8 req_status, u32 * msg)
 {
        static char *FAIL_STATUS[] = {
                "0x80",         /* not used */
@@ -177,9 +93,11 @@ void i2o_report_fail_status(u8 req_status, u32 * msg)
        };
 
        if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
-               printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status);
+               printk(KERN_DEBUG "TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.",
+                      req_status);
        else
-               printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]);
+               printk(KERN_DEBUG "TRANSPORT_%s.\n",
+                      FAIL_STATUS[req_status & 0x0F]);
 
        /* Dump some details */
 
@@ -192,16 +110,17 @@ void i2o_report_fail_status(u8 req_status, u32 * msg)
 
        printk(KERN_ERR "  Severity:  0x%02X ", (msg[4] >> 16) & 0xFF);
        if (msg[4] & (1 << 16))
-               printk("(FormatError), "
+               printk(KERN_DEBUG "(FormatError), "
                       "this msg can never be delivered/processed.\n");
        if (msg[4] & (1 << 17))
-               printk("(PathError), "
+               printk(KERN_DEBUG "(PathError), "
                       "this msg can no longer be delivered/processed.\n");
        if (msg[4] & (1 << 18))
-               printk("(PathState), "
+               printk(KERN_DEBUG "(PathState), "
                       "the system state does not allow delivery.\n");
        if (msg[4] & (1 << 19))
-               printk("(Congestion), resources temporarily not available;"
+               printk(KERN_DEBUG
+                      "(Congestion), resources temporarily not available;"
                       "do not retry immediately.\n");
 }
 
@@ -209,7 +128,7 @@ void i2o_report_fail_status(u8 req_status, u32 * msg)
  * Used for error reporting/debugging purposes.
  * Following reply status are common to all classes.
  */
-void i2o_report_common_status(u8 req_status)
+static void i2o_report_common_status(u8 req_status)
 {
        static char *REPLY_STATUS[] = {
                "SUCCESS",
@@ -227,9 +146,9 @@ void i2o_report_common_status(u8 req_status)
        };
 
        if (req_status >= ARRAY_SIZE(REPLY_STATUS))
-               printk("RequestStatus = %0#2x", req_status);
+               printk(KERN_DEBUG "RequestStatus = %0#2x", req_status);
        else
-               printk("%s", REPLY_STATUS[req_status]);
+               printk(KERN_DEBUG "%s", REPLY_STATUS[req_status]);
 }
 
 /*
@@ -272,9 +191,10 @@ static void i2o_report_common_dsc(u16 detailed_status)
        };
 
        if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
-               printk(" / DetailedStatus = %0#4x.\n", detailed_status);
+               printk(KERN_DEBUG " / DetailedStatus = %0#4x.\n",
+                      detailed_status);
        else
-               printk(" / %s.\n", COMMON_DSC[detailed_status]);
+               printk(KERN_DEBUG " / %s.\n", COMMON_DSC[detailed_status]);
 }
 
 /*
@@ -284,49 +204,49 @@ static void i2o_report_util_cmd(u8 cmd)
 {
        switch (cmd) {
        case I2O_CMD_UTIL_NOP:
-               printk("UTIL_NOP, ");
+               printk(KERN_DEBUG "UTIL_NOP, ");
                break;
        case I2O_CMD_UTIL_ABORT:
-               printk("UTIL_ABORT, ");
+               printk(KERN_DEBUG "UTIL_ABORT, ");
                break;
        case I2O_CMD_UTIL_CLAIM:
-               printk("UTIL_CLAIM, ");
+               printk(KERN_DEBUG "UTIL_CLAIM, ");
                break;
        case I2O_CMD_UTIL_RELEASE:
-               printk("UTIL_CLAIM_RELEASE, ");
+               printk(KERN_DEBUG "UTIL_CLAIM_RELEASE, ");
                break;
        case I2O_CMD_UTIL_CONFIG_DIALOG:
-               printk("UTIL_CONFIG_DIALOG, ");
+               printk(KERN_DEBUG "UTIL_CONFIG_DIALOG, ");
                break;
        case I2O_CMD_UTIL_DEVICE_RESERVE:
-               printk("UTIL_DEVICE_RESERVE, ");
+               printk(KERN_DEBUG "UTIL_DEVICE_RESERVE, ");
                break;
        case I2O_CMD_UTIL_DEVICE_RELEASE:
-               printk("UTIL_DEVICE_RELEASE, ");
+               printk(KERN_DEBUG "UTIL_DEVICE_RELEASE, ");
                break;
        case I2O_CMD_UTIL_EVT_ACK:
-               printk("UTIL_EVENT_ACKNOWLEDGE, ");
+               printk(KERN_DEBUG "UTIL_EVENT_ACKNOWLEDGE, ");
                break;
        case I2O_CMD_UTIL_EVT_REGISTER:
-               printk("UTIL_EVENT_REGISTER, ");
+               printk(KERN_DEBUG "UTIL_EVENT_REGISTER, ");
                break;
        case I2O_CMD_UTIL_LOCK:
-               printk("UTIL_LOCK, ");
+               printk(KERN_DEBUG "UTIL_LOCK, ");
                break;
        case I2O_CMD_UTIL_LOCK_RELEASE:
-               printk("UTIL_LOCK_RELEASE, ");
+               printk(KERN_DEBUG "UTIL_LOCK_RELEASE, ");
                break;
        case I2O_CMD_UTIL_PARAMS_GET:
-               printk("UTIL_PARAMS_GET, ");
+               printk(KERN_DEBUG "UTIL_PARAMS_GET, ");
                break;
        case I2O_CMD_UTIL_PARAMS_SET:
-               printk("UTIL_PARAMS_SET, ");
+               printk(KERN_DEBUG "UTIL_PARAMS_SET, ");
                break;
        case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
-               printk("UTIL_REPLY_FAULT_NOTIFY, ");
+               printk(KERN_DEBUG "UTIL_REPLY_FAULT_NOTIFY, ");
                break;
        default:
-               printk("Cmd = %0#2x, ", cmd);
+               printk(KERN_DEBUG "Cmd = %0#2x, ", cmd);
        }
 }
 
@@ -337,106 +257,106 @@ static void i2o_report_exec_cmd(u8 cmd)
 {
        switch (cmd) {
        case I2O_CMD_ADAPTER_ASSIGN:
-               printk("EXEC_ADAPTER_ASSIGN, ");
+               printk(KERN_DEBUG "EXEC_ADAPTER_ASSIGN, ");
                break;
        case I2O_CMD_ADAPTER_READ:
-               printk("EXEC_ADAPTER_READ, ");
+               printk(KERN_DEBUG "EXEC_ADAPTER_READ, ");
                break;
        case I2O_CMD_ADAPTER_RELEASE:
-               printk("EXEC_ADAPTER_RELEASE, ");
+               printk(KERN_DEBUG "EXEC_ADAPTER_RELEASE, ");
                break;
        case I2O_CMD_BIOS_INFO_SET:
-               printk("EXEC_BIOS_INFO_SET, ");
+               printk(KERN_DEBUG "EXEC_BIOS_INFO_SET, ");
                break;
        case I2O_CMD_BOOT_DEVICE_SET:
-               printk("EXEC_BOOT_DEVICE_SET, ");
+               printk(KERN_DEBUG "EXEC_BOOT_DEVICE_SET, ");
                break;
        case I2O_CMD_CONFIG_VALIDATE:
-               printk("EXEC_CONFIG_VALIDATE, ");
+               printk(KERN_DEBUG "EXEC_CONFIG_VALIDATE, ");
                break;
        case I2O_CMD_CONN_SETUP:
-               printk("EXEC_CONN_SETUP, ");
+               printk(KERN_DEBUG "EXEC_CONN_SETUP, ");
                break;
        case I2O_CMD_DDM_DESTROY:
-               printk("EXEC_DDM_DESTROY, ");
+               printk(KERN_DEBUG "EXEC_DDM_DESTROY, ");
                break;
        case I2O_CMD_DDM_ENABLE:
-               printk("EXEC_DDM_ENABLE, ");
+               printk(KERN_DEBUG "EXEC_DDM_ENABLE, ");
                break;
        case I2O_CMD_DDM_QUIESCE:
-               printk("EXEC_DDM_QUIESCE, ");
+               printk(KERN_DEBUG "EXEC_DDM_QUIESCE, ");
                break;
        case I2O_CMD_DDM_RESET:
-               printk("EXEC_DDM_RESET, ");
+               printk(KERN_DEBUG "EXEC_DDM_RESET, ");
                break;
        case I2O_CMD_DDM_SUSPEND:
-               printk("EXEC_DDM_SUSPEND, ");
+               printk(KERN_DEBUG "EXEC_DDM_SUSPEND, ");
                break;
        case I2O_CMD_DEVICE_ASSIGN:
-               printk("EXEC_DEVICE_ASSIGN, ");
+               printk(KERN_DEBUG "EXEC_DEVICE_ASSIGN, ");
                break;
        case I2O_CMD_DEVICE_RELEASE:
-               printk("EXEC_DEVICE_RELEASE, ");
+               printk(KERN_DEBUG "EXEC_DEVICE_RELEASE, ");
                break;
        case I2O_CMD_HRT_GET:
-               printk("EXEC_HRT_GET, ");
+               printk(KERN_DEBUG "EXEC_HRT_GET, ");
                break;
        case I2O_CMD_ADAPTER_CLEAR:
-               printk("EXEC_IOP_CLEAR, ");
+               printk(KERN_DEBUG "EXEC_IOP_CLEAR, ");
                break;
        case I2O_CMD_ADAPTER_CONNECT:
-               printk("EXEC_IOP_CONNECT, ");
+               printk(KERN_DEBUG "EXEC_IOP_CONNECT, ");
                break;
        case I2O_CMD_ADAPTER_RESET:
-               printk("EXEC_IOP_RESET, ");
+               printk(KERN_DEBUG "EXEC_IOP_RESET, ");
                break;
        case I2O_CMD_LCT_NOTIFY:
-               printk("EXEC_LCT_NOTIFY, ");
+               printk(KERN_DEBUG "EXEC_LCT_NOTIFY, ");
                break;
        case I2O_CMD_OUTBOUND_INIT:
-               printk("EXEC_OUTBOUND_INIT, ");
+               printk(KERN_DEBUG "EXEC_OUTBOUND_INIT, ");
                break;
        case I2O_CMD_PATH_ENABLE:
-               printk("EXEC_PATH_ENABLE, ");
+               printk(KERN_DEBUG "EXEC_PATH_ENABLE, ");
                break;
        case I2O_CMD_PATH_QUIESCE:
-               printk("EXEC_PATH_QUIESCE, ");
+               printk(KERN_DEBUG "EXEC_PATH_QUIESCE, ");
                break;
        case I2O_CMD_PATH_RESET:
-               printk("EXEC_PATH_RESET, ");
+               printk(KERN_DEBUG "EXEC_PATH_RESET, ");
                break;
        case I2O_CMD_STATIC_MF_CREATE:
-               printk("EXEC_STATIC_MF_CREATE, ");
+               printk(KERN_DEBUG "EXEC_STATIC_MF_CREATE, ");
                break;
        case I2O_CMD_STATIC_MF_RELEASE:
-               printk("EXEC_STATIC_MF_RELEASE, ");
+               printk(KERN_DEBUG "EXEC_STATIC_MF_RELEASE, ");
                break;
        case I2O_CMD_STATUS_GET:
-               printk("EXEC_STATUS_GET, ");
+               printk(KERN_DEBUG "EXEC_STATUS_GET, ");
                break;
        case I2O_CMD_SW_DOWNLOAD:
-               printk("EXEC_SW_DOWNLOAD, ");
+               printk(KERN_DEBUG "EXEC_SW_DOWNLOAD, ");
                break;
        case I2O_CMD_SW_UPLOAD:
-               printk("EXEC_SW_UPLOAD, ");
+               printk(KERN_DEBUG "EXEC_SW_UPLOAD, ");
                break;
        case I2O_CMD_SW_REMOVE:
-               printk("EXEC_SW_REMOVE, ");
+               printk(KERN_DEBUG "EXEC_SW_REMOVE, ");
                break;
        case I2O_CMD_SYS_ENABLE:
-               printk("EXEC_SYS_ENABLE, ");
+               printk(KERN_DEBUG "EXEC_SYS_ENABLE, ");
                break;
        case I2O_CMD_SYS_MODIFY:
-               printk("EXEC_SYS_MODIFY, ");
+               printk(KERN_DEBUG "EXEC_SYS_MODIFY, ");
                break;
        case I2O_CMD_SYS_QUIESCE:
-               printk("EXEC_SYS_QUIESCE, ");
+               printk(KERN_DEBUG "EXEC_SYS_QUIESCE, ");
                break;
        case I2O_CMD_SYS_TAB_SET:
-               printk("EXEC_SYS_TAB_SET, ");
+               printk(KERN_DEBUG "EXEC_SYS_TAB_SET, ");
                break;
        default:
-               printk("Cmd = %#02x, ", cmd);
+               printk(KERN_DEBUG "Cmd = %#02x, ", cmd);
        }
 }
 
@@ -445,46 +365,32 @@ 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");
+               printk(KERN_DEBUG "INIT\n");
                break;
        case 0x02:
-               printk("RESET\n");
+               printk(KERN_DEBUG "RESET\n");
                break;
        case 0x04:
-               printk("HOLD\n");
+               printk(KERN_DEBUG "HOLD\n");
                break;
        case 0x05:
-               printk("READY\n");
+               printk(KERN_DEBUG "READY\n");
                break;
        case 0x08:
-               printk("OPERATIONAL\n");
+               printk(KERN_DEBUG "OPERATIONAL\n");
                break;
        case 0x10:
-               printk("FAILED\n");
+               printk(KERN_DEBUG "FAILED\n");
                break;
        case 0x11:
-               printk("FAULTED\n");
+               printk(KERN_DEBUG "FAULTED\n");
                break;
        default:
-               printk("%x (unknown !!)\n",
+               printk(KERN_DEBUG "%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;
@@ -516,56 +422,60 @@ void i2o_dump_hrt(struct i2o_controller *c)
                d = (u8 *) (rows + 2);
                state = p[1] << 8 | p[0];
 
-               printk("TID %04X:[", state & 0xFFF);
+               printk(KERN_DEBUG "TID %04X:[", state & 0xFFF);
                state >>= 12;
                if (state & (1 << 0))
-                       printk("H");    /* Hidden */
+                       printk(KERN_DEBUG "H"); /* Hidden */
                if (state & (1 << 2)) {
-                       printk("P");    /* Present */
+                       printk(KERN_DEBUG "P"); /* Present */
                        if (state & (1 << 1))
-                               printk("C");    /* Controlled */
+                               printk(KERN_DEBUG "C"); /* Controlled */
                }
                if (state > 9)
-                       printk("*");    /* Hard */
+                       printk(KERN_DEBUG "*"); /* Hard */
 
-               printk("]:");
+               printk(KERN_DEBUG "]:");
 
                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));
+                       printk(KERN_DEBUG
+                              "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));
+                       printk(KERN_DEBUG
+                              "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",
+                       printk(KERN_DEBUG
+                              "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));
+                       printk(KERN_DEBUG
+                              "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]);
+                       printk(KERN_DEBUG
+                              "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.");
+                       printk(KERN_DEBUG "Unsupported bus type.");
                        break;
                }
-               printk("\n");
+               printk(KERN_DEBUG "\n");
                rows += length;
        }
 }
 
-EXPORT_SYMBOL(i2o_dump_status_block);
 EXPORT_SYMBOL(i2o_dump_message);
index ff4822e..e4f9235 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/module.h>
 #include <linux/i2o.h>
+#include <linux/delay.h>
 
 /* Exec OSM functions */
 extern struct bus_type i2o_bus_type;
@@ -34,7 +35,7 @@ extern struct bus_type i2o_bus_type;
 static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd,
                                         u32 type)
 {
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        u32 m;
 
        m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET);
@@ -106,8 +107,7 @@ int i2o_device_claim_release(struct i2o_device *dev)
                if (!rc)
                        break;
 
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ);
+               ssleep(1);
        }
 
        if (!rc)
@@ -211,8 +211,8 @@ static struct i2o_device *i2o_device_alloc(void)
  *     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)
+static struct i2o_device *i2o_device_add(struct i2o_controller *c,
+                                        i2o_lct_entry * entry)
 {
        struct i2o_device *dev;
 
@@ -446,7 +446,7 @@ static struct class_interface i2o_device_class_interface = {
 int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
                   int oplen, void *reslist, int reslen)
 {
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        u32 m;
        u32 *res32 = (u32 *) reslist;
        u32 *restmp = (u32 *) reslist;
@@ -546,47 +546,6 @@ int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field,
        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
@@ -669,6 +628,5 @@ void i2o_device_exit(void)
 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);
index bc69d66..388a443 100644 (file)
 #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 spinlock_t i2o_drivers_lock;
 static struct i2o_driver **i2o_drivers;
 
 /**
@@ -146,7 +145,7 @@ void i2o_driver_unregister(struct i2o_driver *drv)
                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_device_remove(drv, i2o_dev);
 
                i2o_driver_notify_controller_remove(drv, c);
        }
@@ -176,7 +175,7 @@ void i2o_driver_unregister(struct i2o_driver *drv)
  *     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_message __iomem *msg)
 {
        struct i2o_driver *drv;
        u32 context = readl(&msg->u.s.icntxt);
@@ -246,14 +245,15 @@ int i2o_driver_dispatch(struct i2o_controller *c, u32 m,
  *     Send notifications to all registered drivers that a new controller was
  *     added.
  */
-void i2o_driver_notify_controller_add_all(struct i2o_controller *c) {
+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 ++) {
+       for (i = 0; i < I2O_MAX_DRIVERS; i++) {
                drv = i2o_drivers[i];
 
-               if(drv)
+               if (drv)
                        i2o_driver_notify_controller_add(drv, c);
        }
 }
@@ -265,14 +265,15 @@ void i2o_driver_notify_controller_add_all(struct i2o_controller *c) {
  *     Send notifications to all registered drivers that a controller was
  *     removed.
  */
-void i2o_driver_notify_controller_remove_all(struct i2o_controller *c) {
+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 ++) {
+       for (i = 0; i < I2O_MAX_DRIVERS; i++) {
                drv = i2o_drivers[i];
 
-               if(drv)
+               if (drv)
                        i2o_driver_notify_controller_remove(drv, c);
        }
 }
@@ -283,14 +284,15 @@ void i2o_driver_notify_controller_remove_all(struct i2o_controller *c) {
  *
  *     Send notifications to all registered drivers that a device was added.
  */
-void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev) {
+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 ++) {
+       for (i = 0; i < I2O_MAX_DRIVERS; i++) {
                drv = i2o_drivers[i];
 
-               if(drv)
+               if (drv)
                        i2o_driver_notify_device_add(drv, i2o_dev);
        }
 }
@@ -301,14 +303,15 @@ void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev) {
  *
  *     Send notifications to all registered drivers that a device was removed.
  */
-void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev) {
+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 ++) {
+       for (i = 0; i < I2O_MAX_DRIVERS; i++) {
                drv = i2o_drivers[i];
 
-               if(drv)
+               if (drv)
                        i2o_driver_notify_device_remove(drv, i2o_dev);
        }
 }
@@ -324,6 +327,8 @@ int __init i2o_driver_init(void)
 {
        int rc = 0;
 
+       spin_lock_init(&i2o_drivers_lock);
+
        if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64) ||
            ((i2o_max_drivers ^ (i2o_max_drivers - 1)) !=
             (2 * i2o_max_drivers - 1))) {
index 117f261..b25dc61 100644 (file)
 
 #include <linux/module.h>
 #include <linux/i2o.h>
+#include <linux/delay.h>
 
 struct i2o_driver i2o_exec_driver;
 
+static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind);
+
 /* Module internal functions from other sources */
 extern int i2o_device_parse_lct(struct i2o_controller *);
 
@@ -45,7 +48,7 @@ struct i2o_exec_wait {
        u32 tcntxt;             /* transaction context from reply */
        int complete;           /* 1 if reply received otherwise 0 */
        u32 m;                  /* message id */
-       struct i2o_message *msg;        /* pointer to the reply message */
+       struct i2o_message __iomem *msg;        /* pointer to the reply message */
        struct list_head list;  /* node in global wait list */
 };
 
@@ -109,21 +112,20 @@ 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;
+       struct i2o_exec_wait *wait;
        static u32 tcntxt = 0x80000000;
-       struct i2o_message *msg = c->in_queue.virt + m;
+       struct i2o_message __iomem *msg = c->in_queue.virt + m;
        int rc = 0;
 
-       iwait = i2o_exec_wait_alloc();
-       if (!iwait)
+       wait = i2o_exec_wait_alloc();
+       if (!wait)
                return -ENOMEM;
 
        if (tcntxt == 0xffffffff)
                tcntxt = 0x80000000;
 
        if (dma)
-               iwait->dma = *dma;
+               wait->dma = *dma;
 
        /*
         * Fill in the message initiator context and transaction context.
@@ -131,8 +133,8 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
         * 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);
+       wait->tcntxt = tcntxt++;
+       writel(wait->tcntxt, &msg->u.s.tcntxt);
 
        /*
         * Post the message to the controller. At some point later it will
@@ -140,31 +142,27 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
         */
        i2o_msg_post(c, m);
 
-       if (!iwait->complete) {
-               iwait->wq = &wq;
+       if (!wait->complete) {
+               wait->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);
+               list_add(&wait->list, &i2o_exec_wait_list);
 
-               prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE);
+               wait_event_interruptible_timeout(wq, wait->complete,
+                       timeout * HZ);
 
-               if (!iwait->complete)
-                       schedule_timeout(timeout * HZ);
-
-               finish_wait(&wq, &wait);
-
-               iwait->wq = NULL;
+               wait->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);
+       if (wait->complete) {
+               if (readl(&wait->msg->body[0]) >> 24)
+                       rc = readl(&wait->msg->body[0]) & 0xff;
+               i2o_flush_reply(c, wait->m);
+               i2o_exec_wait_free(wait);
        } else {
                /*
                 * We cannot remove it now. This is important. When it does
@@ -201,13 +199,15 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
  *     message must also be given back to the controller.
  */
 static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
-                                     struct i2o_message *msg)
+                                     struct i2o_message __iomem *msg)
 {
        struct i2o_exec_wait *wait, *tmp;
-       static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+       static spinlock_t lock;
        int rc = 1;
        u32 context;
 
+       spin_lock_init(&lock);
+
        context = readl(&msg->u.s.tcntxt);
 
        /*
@@ -322,13 +322,13 @@ static void i2o_exec_lct_modified(struct i2o_controller *c)
 static int i2o_exec_reply(struct i2o_controller *c, u32 m,
                          struct i2o_message *msg)
 {
-       if (readl(&msg->u.head[0]) & MSG_FAIL) {        // Fail bit is set
-               struct i2o_message *pmsg;       /* preserved message */
+       if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {   // Fail bit is set
+               struct i2o_message __iomem *pmsg;       /* preserved message */
                u32 pm;
 
-               pm = readl(&msg->body[3]);
+               pm = le32_to_cpu(msg->body[3]);
 
-               pmsg = c->in_queue.virt + pm;
+               pmsg = i2o_msg_in_to_virt(c, pm);
 
                i2o_report_status(KERN_INFO, "i2o_core", msg);
 
@@ -339,10 +339,10 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m,
                return -1;
        }
 
-       if (readl(&msg->u.s.tcntxt) & 0x80000000)
+       if (le32_to_cpu(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) {
+       if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
                struct work_struct *work;
 
                pr_debug("%s: LCT notify received\n", c->name);
@@ -395,7 +395,7 @@ static void i2o_exec_event(struct i2o_event *evt)
  */
 int i2o_exec_lct_get(struct i2o_controller *c)
 {
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        u32 m;
        int i = 0;
        int rc = -EAGAIN;
@@ -435,11 +435,11 @@ int i2o_exec_lct_get(struct i2o_controller *c)
  *     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)
+static 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;
+       struct i2o_message __iomem *msg;
        u32 m;
 
        dev = &c->pdev->dev;
@@ -502,4 +502,3 @@ void __exit i2o_exec_exit(void)
 
 EXPORT_SYMBOL(i2o_msg_post_wait_mem);
 EXPORT_SYMBOL(i2o_exec_lct_get);
-EXPORT_SYMBOL(i2o_exec_lct_notify);
index 699723e..ea6a8b3 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/module.h>
 #include <linux/i2o.h>
+#include <linux/delay.h>
 
 /* global I2O controller list */
 LIST_HEAD(i2o_controllers);
@@ -37,6 +38,8 @@ LIST_HEAD(i2o_controllers);
  */
 static struct i2o_dma i2o_systab;
 
+static int i2o_hrt_get(struct i2o_controller *c);
+
 /* Module internal functions from other sources */
 extern struct i2o_driver i2o_exec_driver;
 extern int i2o_exec_lct_get(struct i2o_controller *);
@@ -62,7 +65,7 @@ extern void i2o_device_exit(void);
  */
 void i2o_msg_nop(struct i2o_controller *c, u32 m)
 {
-       struct i2o_message *msg = c->in_queue.virt + m;
+       struct i2o_message __iomem *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,
@@ -86,7 +89,7 @@ void i2o_msg_nop(struct i2o_controller *c, u32 m)
  *     address from the read port (see the i2o spec). If no message is
  *     available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
  */
-u32 i2o_msg_get_wait(struct i2o_controller *c, struct i2o_message **msg,
+u32 i2o_msg_get_wait(struct i2o_controller *c, struct i2o_message __iomem **msg,
                     int wait)
 {
        unsigned long timeout = jiffies + wait * HZ;
@@ -117,7 +120,7 @@ u32 i2o_msg_get_wait(struct i2o_controller *c, struct i2o_message **msg,
  *
  *     Returns context id > 0 on success or 0 on failure.
  */
-u32 i2o_cntxt_list_add(struct i2o_controller *c, void *ptr)
+u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
 {
        struct i2o_context_list_element *entry;
        unsigned long flags;
@@ -162,7 +165,7 @@ u32 i2o_cntxt_list_add(struct i2o_controller *c, void *ptr)
  *
  *     Returns context id on succes or 0 on failure.
  */
-u32 i2o_cntxt_list_remove(struct i2o_controller *c, void *ptr)
+u32 i2o_cntxt_list_remove(struct i2o_controller * c, void *ptr)
 {
        struct i2o_context_list_element *entry;
        u32 context = 0;
@@ -303,7 +306,7 @@ struct i2o_device *i2o_iop_find_device(struct i2o_controller *c, u16 tid)
  */
 static int i2o_iop_quiesce(struct i2o_controller *c)
 {
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        u32 m;
        i2o_status_block *sb = c->status_block.virt;
        int rc;
@@ -345,7 +348,7 @@ static int i2o_iop_quiesce(struct i2o_controller *c)
  */
 static int i2o_iop_enable(struct i2o_controller *c)
 {
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        u32 m;
        i2o_status_block *sb = c->status_block.virt;
        int rc;
@@ -417,7 +420,7 @@ static inline void i2o_iop_enable_all(void)
  */
 static int i2o_iop_clear(struct i2o_controller *c)
 {
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        u32 m;
        int rc;
 
@@ -458,7 +461,7 @@ static int i2o_iop_clear(struct i2o_controller *c)
 static int i2o_iop_reset(struct i2o_controller *c)
 {
        u8 *status = c->status.virt;
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        u32 m;
        unsigned long timeout;
        i2o_status_block *sb = c->status_block.virt;
@@ -470,7 +473,7 @@ static int i2o_iop_reset(struct i2o_controller *c)
        if (m == I2O_QUEUE_EMPTY)
                return -ETIMEDOUT;
 
-       memset(status, 0, 4);
+       memset(status, 0, 8);
 
        /* Quiesce all IOPs first */
        i2o_iop_quiesce_all();
@@ -495,6 +498,13 @@ static int i2o_iop_reset(struct i2o_controller *c)
                        rc = -ETIMEDOUT;
                        goto exit;
                }
+
+               /* Promise bug */
+               if (status[1] || status[4]) {
+                       *status = 0;
+                       break;
+               }
+
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(1);
 
@@ -556,11 +566,11 @@ static int i2o_iop_reset(struct i2o_controller *c)
  *
  *     Returns 0 on success or a negative errno code on failure.
  */
-int i2o_iop_init_outbound_queue(struct i2o_controller *c)
+static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
 {
        u8 *status = c->status.virt;
        u32 m;
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        ulong timeout;
        int i;
 
@@ -605,12 +615,30 @@ int i2o_iop_init_outbound_queue(struct i2o_controller *c)
        /* Post frames */
        for (i = 0; i < NMBR_MSG_FRAMES; i++) {
                i2o_flush_reply(c, m);
+               udelay(1);      /* Promise */
                m += MSG_FRAME_SIZE * 4;
        }
 
        return 0;
 }
 
+/**
+ *     i2o_iop_send_nop - send a core NOP message
+ *     @c: controller
+ *
+ *     Send a no-operation message with a reply set to cause no
+ *     action either. Needed for bringing up promise controllers.
+ */
+static int i2o_iop_send_nop(struct i2o_controller *c)
+{
+       struct i2o_message __iomem *msg;
+       u32 m = i2o_msg_get_wait(c, &msg, HZ);
+       if (m == I2O_QUEUE_EMPTY)
+               return -ETIMEDOUT;
+       i2o_msg_nop(c, m);
+       return 0;
+}
+
 /**
  *     i2o_iop_activate - Bring controller up to HOLD
  *     @c: controller
@@ -622,8 +650,27 @@ int i2o_iop_init_outbound_queue(struct i2o_controller *c)
  */
 static int i2o_iop_activate(struct i2o_controller *c)
 {
+       struct pci_dev *i960 = NULL;
        i2o_status_block *sb = c->status_block.virt;
        int rc;
+
+       if (c->promise) {
+               /* Beat up the hardware first of all */
+               i960 =
+                   pci_find_slot(c->pdev->bus->number,
+                                 PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
+               if (i960)
+                       pci_write_config_word(i960, 0x42, 0);
+
+               /* Follow this sequence precisely or the controller
+                  ceases to perform useful functions until reboot */
+               if ((rc = i2o_iop_send_nop(c)))
+                       return rc;
+
+               if ((rc = i2o_iop_reset(c)))
+                       return rc;
+       }
+
        /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
        /* In READY state, Get status */
 
@@ -659,13 +706,22 @@ static int i2o_iop_activate(struct i2o_controller *c)
        if (rc)
                return rc;
 
+       if (c->promise) {
+               if ((rc = i2o_iop_send_nop(c)))
+                       return rc;
+
+               if ((rc = i2o_status_get(c)))
+                       return rc;
+
+               if (i960)
+                       pci_write_config_word(i960, 0x42, 0x3FF);
+       }
+
        /* In HOLD state */
 
        rc = i2o_hrt_get(c);
-       if (rc)
-               return rc;
 
-       return 0;
+       return rc;
 };
 
 /**
@@ -678,7 +734,7 @@ static int i2o_iop_activate(struct i2o_controller *c)
  */
 static int i2o_iop_systab_set(struct i2o_controller *c)
 {
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        u32 m;
        i2o_status_block *sb = c->status_block.virt;
        struct device *dev = &c->pdev->dev;
@@ -691,10 +747,11 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
                res->flags = IORESOURCE_MEM;
                res->start = 0;
                res->end = 0;
-               printk("%s: requires private memory resources.\n", c->name);
+               printk(KERN_INFO "%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");
+                       printk(KERN_WARNING "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;
@@ -712,10 +769,11 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
                res->flags = IORESOURCE_IO;
                res->start = 0;
                res->end = 0;
-               printk("%s: requires private memory resources.\n", c->name);
+               printk(KERN_INFO "%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");
+                       printk(KERN_WARNING "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;
@@ -754,7 +812,7 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
 
        writel(c->unit + 2, &msg->body[0]);
        writel(0, &msg->body[1]);
-       writel(0x54000000 | i2o_systab.phys, &msg->body[2]);
+       writel(0x54000000 | i2o_systab.len, &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]);
@@ -939,7 +997,7 @@ static int i2o_parse_hrt(struct i2o_controller *c)
  */
 int i2o_status_get(struct i2o_controller *c)
 {
-       struct i2o_message *msg;
+       struct i2o_message __iomem *msg;
        u32 m;
        u8 *status_block;
        unsigned long timeout;
@@ -994,7 +1052,7 @@ int i2o_status_get(struct i2o_controller *c)
  *
  *     Returns 0 on success or negativer error code on failure.
  */
-int i2o_hrt_get(struct i2o_controller *c)
+static int i2o_hrt_get(struct i2o_controller *c)
 {
        int rc;
        int i;
@@ -1003,7 +1061,7 @@ int i2o_hrt_get(struct i2o_controller *c)
        struct device *dev = &c->pdev->dev;
 
        for (i = 0; i < I2O_HRT_GET_TRIES; i++) {
-               struct i2o_message *msg;
+               struct i2o_message __iomem *msg;
                u32 m;
 
                m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
@@ -1063,13 +1121,13 @@ struct i2o_controller *i2o_iop_alloc(void)
        memset(c, 0, sizeof(*c));
 
        INIT_LIST_HEAD(&c->devices);
-       c->lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&c->lock);
        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;
+       spin_lock_init(&c->context_list_lock);
        atomic_set(&c->context_list_counter, 0);
        INIT_LIST_HEAD(&c->context_list);
 #endif
@@ -1158,7 +1216,7 @@ 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;
+       struct i2o_message __iomem *msg;
        u32 m;
 
        m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
@@ -1254,5 +1312,4 @@ 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);
index 9ee58b6..f98849a 100644 (file)
@@ -138,13 +138,13 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
                                 * 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)
+                               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)
+                                               if (c->base.len > 0x100000)
                                                        c->base.len = 0x100000;
                                        }
                                }
@@ -231,7 +231,7 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
        }
 #endif
 
-       if (i2o_dma_alloc(dev, &c->status, 4, GFP_KERNEL)) {
+       if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) {
                i2o_pci_free(c);
                return -ENOMEM;
        }
@@ -277,7 +277,6 @@ static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
        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
@@ -298,11 +297,7 @@ static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
                 * 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;
+               m = i2o_msg_out_to_virt(c, mv);
 
                /*
                 *      Ensure this message is seen coherently but cachably by
index 9b3ff1d..6fec7fd 100644 (file)
@@ -158,7 +158,7 @@ struct remote_queue {
 struct service_processor {
        struct list_head        node;
        spinlock_t              lock;
-       void                    *base_address;
+       void __iomem            *base_address;
        unsigned int            irq;
        struct command          *current_command;
        struct command          *heartbeat;
index 3b3e631..5156de2 100644 (file)
@@ -58,7 +58,7 @@ irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *reg
 {
        u32     mfa;
        struct service_processor *sp = (struct service_processor *)dev_id;
-       void *base_address = sp->base_address;
+       void __iomem *base_address = sp->base_address;
 
        if (!sp_interrupt_pending(base_address))
                return IRQ_NONE;
index 4339504..e5ed59c 100644 (file)
 #define SCOUT_COM_C_BASE         0x0200   
 #define SCOUT_COM_D_BASE         0x0300   
 
-static inline int sp_interrupt_pending(void *base_address)
+static inline int sp_interrupt_pending(void __iomem *base_address)
 {
        return SP_INTR_MASK & readl(base_address + INTR_STATUS_REGISTER);
 }
 
-static inline int uart_interrupt_pending(void *base_address)
+static inline int uart_interrupt_pending(void __iomem *base_address)
 {
        return UART_INTR_MASK & readl(base_address + INTR_STATUS_REGISTER);
 }
 
-static inline void ibmasm_enable_interrupts(void *base_address, int mask)
+static inline void ibmasm_enable_interrupts(void __iomem *base_address, int mask)
 {
-       void *ctrl_reg = base_address + INTR_CONTROL_REGISTER;
+       void __iomem *ctrl_reg = base_address + INTR_CONTROL_REGISTER;
        writel( readl(ctrl_reg) & ~mask, ctrl_reg);
 }
 
-static inline void ibmasm_disable_interrupts(void *base_address, int mask)
+static inline void ibmasm_disable_interrupts(void __iomem *base_address, int mask)
 {
-       void *ctrl_reg = base_address + INTR_CONTROL_REGISTER;
+       void __iomem *ctrl_reg = base_address + INTR_CONTROL_REGISTER;
        writel( readl(ctrl_reg) | mask, ctrl_reg);
 }
 
-static inline void enable_sp_interrupts(void *base_address)
+static inline void enable_sp_interrupts(void __iomem *base_address)
 {
        ibmasm_enable_interrupts(base_address, SP_INTR_MASK);
 }
 
-static inline void disable_sp_interrupts(void *base_address)
+static inline void disable_sp_interrupts(void __iomem *base_address)
 {
        ibmasm_disable_interrupts(base_address, SP_INTR_MASK);
 }
 
-static inline void enable_uart_interrupts(void *base_address)
+static inline void enable_uart_interrupts(void __iomem *base_address)
 {
        ibmasm_enable_interrupts(base_address, UART_INTR_MASK); 
 }
 
-static inline void disable_uart_interrupts(void *base_address)
+static inline void disable_uart_interrupts(void __iomem *base_address)
 {
        ibmasm_disable_interrupts(base_address, UART_INTR_MASK); 
 }
 
 #define valid_mfa(mfa) ( (mfa) != NO_MFAS_AVAILABLE )
 
-static inline u32 get_mfa_outbound(void *base_address)
+static inline u32 get_mfa_outbound(void __iomem *base_address)
 {
        int retry;
        u32 mfa;
@@ -109,12 +109,12 @@ static inline u32 get_mfa_outbound(void *base_address)
        return mfa;
 }
 
-static inline void set_mfa_outbound(void *base_address, u32 mfa)
+static inline void set_mfa_outbound(void __iomem *base_address, u32 mfa)
 {
        writel(mfa, base_address + OUTBOUND_QUEUE_PORT);
 }
 
-static inline u32 get_mfa_inbound(void *base_address)
+static inline u32 get_mfa_inbound(void __iomem *base_address)
 {
        u32 mfa = readl(base_address + INBOUND_QUEUE_PORT);
 
@@ -124,12 +124,12 @@ static inline u32 get_mfa_inbound(void *base_address)
        return mfa;
 }
 
-static inline void set_mfa_inbound(void *base_address, u32 mfa)
+static inline void set_mfa_inbound(void __iomem *base_address, u32 mfa)
 {
        writel(mfa, base_address + INBOUND_QUEUE_PORT);
 }
 
-static inline struct i2o_message *get_i2o_message(void *base_address, u32 mfa)
+static inline struct i2o_message *get_i2o_message(void __iomem *base_address, u32 mfa)
 {
        return (struct i2o_message *)(GET_MFA_ADDR(mfa) + base_address);
 }
index 604b87e..9148045 100644 (file)
@@ -34,7 +34,7 @@
 void ibmasm_register_uart(struct service_processor *sp)
 {
        struct serial_struct serial;
-       unsigned char *iomem_base;
+       void __iomem *iomem_base;
 
        iomem_base = sp->base_address + SCOUT_COM_B_BASE;
 
index 6b1b517..21becb1 100644 (file)
@@ -49,4 +49,15 @@ config MMC_PXA
 
          If unsure, say N.
 
+config MMC_WBSD
+       tristate "Winbond W83L51xD SD/MMC Card Interface support"
+       depends on MMC
+       help
+         This selects the Winbond(R) W83L51xD Secure digital and
+          Multimedia card Interface.
+         If you have a machine with a integrated W83L518D or W83L519D
+         SD/MMC card reader, say Y or M here.
+
+         If unsure, say N.
+
 endmenu
index def0111..89510c2 100644 (file)
@@ -17,5 +17,6 @@ obj-$(CONFIG_MMC_BLOCK)               += mmc_block.o
 #
 obj-$(CONFIG_MMC_ARMMMCI)      += mmci.o
 obj-$(CONFIG_MMC_PXA)          += pxamci.o
+obj-$(CONFIG_MMC_WBSD)         += wbsd.o
 
 mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
index f76673a..46d884e 100644 (file)
@@ -200,6 +200,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                }
                brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL;
 
+               brq.data.sg = mq->sg;
+               brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
+
                mmc_wait_for_req(card->host, &brq.mrq);
                if (brq.cmd.error) {
                        printk(KERN_ERR "%s: error %d sending read/write command\n",
index e818b92..0b9682e 100644 (file)
@@ -80,7 +80,7 @@ static int mmc_queue_thread(void *d)
                set_current_state(TASK_INTERRUPTIBLE);
                if (!blk_queue_plugged(q))
                        mq->req = req = elv_next_request(q);
-               spin_unlock(q->queue_lock);
+               spin_unlock_irq(q->queue_lock);
 
                if (!req) {
                        if (mq->flags & MMC_QUEUE_EXIT)
@@ -147,19 +147,31 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
        mq->queue->queuedata = mq;
        mq->req = NULL;
 
+       mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs,
+                        GFP_KERNEL);
+       if (!mq->sg) {
+               ret = -ENOMEM;
+               goto cleanup;
+       }
+
        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 {
+       if (ret >= 0) {
                wait_for_completion(&mq->thread_complete);
                init_completion(&mq->thread_complete);
                ret = 0;
+               goto out;
        }
 
+ cleanup:
+       kfree(mq->sg);
+       mq->sg = NULL;
+
+       blk_cleanup_queue(mq->queue);
+ out:
        return ret;
 }
 EXPORT_SYMBOL(mmc_init_queue);
@@ -169,6 +181,10 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
        mq->flags |= MMC_QUEUE_EXIT;
        wake_up(&mq->thread_wq);
        wait_for_completion(&mq->thread_complete);
+
+       kfree(mq->sg);
+       mq->sg = NULL;
+
        blk_cleanup_queue(mq->queue);
 
        mq->card = NULL;
index 6bef900..7182d2f 100644 (file)
@@ -15,6 +15,7 @@ struct mmc_queue {
        int                     (*issue_fn)(struct mmc_queue *, struct request *);
        void                    *data;
        struct request_queue    *queue;
+       struct scatterlist      *sg;
 };
 
 struct mmc_io_request {
index 47e1636..dd592d0 100644 (file)
@@ -69,7 +69,7 @@ static void mmci_stop_data(struct mmci_host *host)
 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 {
        unsigned int datactrl, timeout, irqmask;
-       void *base;
+       void __iomem *base;
 
        DBG(host, "blksz %04x blks %04x flags %08x\n",
            1 << data->blksz_bits, data->blocks, data->flags);
@@ -108,7 +108,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 static void
 mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
 {
-       void *base = host->base;
+       void __iomem *base = host->base;
 
        DBG(host, "op %02x arg %08x flags %08x\n",
            cmd->opcode, cmd->arg, cmd->flags);
@@ -169,7 +169,7 @@ static void
 mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
             unsigned int status)
 {
-       void *base = host->base;
+       void __iomem *base = host->base;
 
        host->cmd = NULL;
 
@@ -193,7 +193,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 
 static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
 {
-       void *base = host->base;
+       void __iomem *base = host->base;
        char *ptr = buffer;
        u32 status;
 
@@ -222,7 +222,7 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
 
 static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
 {
-       void *base = host->base;
+       void __iomem *base = host->base;
        char *ptr = buffer;
 
        do {
@@ -251,7 +251,7 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
 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;
+       void __iomem *base = host->base;
        u32 status;
 
        status = readl(base + MMCISTATUS);
@@ -501,7 +501,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
         * We can do SGIO
         */
        mmc->max_hw_segs = 16;
-       mmc->max_phys_segs = 16;
+       mmc->max_phys_segs = NR_SG;
 
        /*
         * Since we only have a 16-bit data length register, we must
index ce3a026..4589bbd 100644 (file)
 struct clk;
 
 struct mmci_host {
-       void                    *base;
+       void __iomem            *base;
        struct mmc_request      *mrq;
        struct mmc_command      *cmd;
        struct mmc_data         *data;
@@ -139,7 +139,6 @@ struct mmci_host {
        struct timer_list       timer;
        unsigned int            oldstat;
 
-       struct scatterlist      sg[NR_SG];
        unsigned int            sg_len;
 
        /* pio stuff */
@@ -150,14 +149,11 @@ struct mmci_host {
 
 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_len = data->sg_len;
+       host->sg_ptr = data->sg;
        host->sg_off = 0;
 }
 
index 23a5091..97ee26d 100644 (file)
 #define DBG(x...)      do { } while (0)
 #endif
 
+#define DRIVER_NAME    "pxa2xx-mci"
+
+#define NR_SG  1
+
 struct pxamci_host {
        struct mmc_host         *mmc;
        spinlock_t              lock;
@@ -63,17 +67,11 @@ struct pxamci_host {
 
        dma_addr_t              sg_dma;
        struct pxa_dma_desc     *sg_cpu;
+       unsigned int            dma_len;
 
-       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;
@@ -122,8 +120,7 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
 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;
+       unsigned int timeout;
        u32 dcmd;
        int i;
 
@@ -152,35 +149,22 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 
        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;
+       host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+                                  host->dma_dir);
 
+       for (i = 0; i < host->dma_len; i++) {
                if (data->flags & MMC_DATA_READ) {
                        host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
-                       host->sg_cpu[i].dtadr = dma;
+                       host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
                } else {
-                       host->sg_cpu[i].dsadr = dma;
+                       host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
                        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;
-               }
+               host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
+               host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
+                                       sizeof(struct pxa_dma_desc);
        }
+       host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
        wmb();
 
        DDADR(host->dma) = host->sg_dma;
@@ -255,7 +239,24 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
        if (stat & STAT_TIME_OUT_RESPONSE) {
                cmd->error = MMC_ERR_TIMEOUT;
        } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
+#ifdef CONFIG_PXA27x
+               /*
+                * workaround for erratum #42:
+                * Intel PXA27x Family Processor Specification Update Rev 001
+                */
+               if (cmd->opcode == MMC_ALL_SEND_CID ||
+                   cmd->opcode == MMC_SEND_CSD ||
+                   cmd->opcode == MMC_SEND_CID) {
+                       /* a bogus CRC error can appear if the msb of
+                          the 15 byte response is a one */
+                       if ((cmd->resp[0] & 0x80000000) == 0)
+                               cmd->error = MMC_ERR_BADCRC;
+               } else {
+                       DBG("ignoring CRC from command %d - *risky*\n",cmd->opcode);
+               }
+#else
                cmd->error = MMC_ERR_BADCRC;
+#endif
        }
 
        pxamci_disable_irq(host, END_CMD_RES);
@@ -276,8 +277,8 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
                return 0;
 
        DCSR(host->dma) = 0;
-       dma_unmap_single(mmc_dev(host->mmc), host->dma_buf, host->dma_size,
-                        host->dma_dir);
+       dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+                    host->dma_dir);
 
        if (stat & STAT_READ_TIME_OUT)
                data->error = MMC_ERR_TIMEOUT;
@@ -374,15 +375,14 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (CLOCKRATE / clk > ios->clock)
                        clk <<= 1;
                host->clkrt = fls(clk) - 1;
+               pxa_set_cken(CKEN12_MMC, 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);
+       } else {
+               pxamci_stop_clock(host);
+               pxa_set_cken(CKEN12_MMC, 0);
        }
 
        if (host->power_mode != ios->power_mode) {
@@ -429,7 +429,7 @@ static int pxamci_probe(struct device *dev)
        if (!r || irq == NO_IRQ)
                return -ENXIO;
 
-       r = request_mem_region(r->start, SZ_4K, "PXAMCI");
+       r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
        if (!r)
                return -EBUSY;
 
@@ -440,8 +440,19 @@ static int pxamci_probe(struct device *dev)
        }
 
        mmc->ops = &pxamci_ops;
-       mmc->f_min = 312500;
-       mmc->f_max = 20000000;
+       mmc->f_min = CLOCKRATE_MIN;
+       mmc->f_max = CLOCKRATE_MAX;
+
+       /*
+        * We can do SG-DMA, but we don't because we never know how much
+        * data we successfully wrote to the card.
+        */
+       mmc->max_phys_segs = NR_SG;
+
+       /*
+        * Our hardware DMA can handle a maximum of one page per SG entry.
+        */
+       mmc->max_seg_size = PAGE_SIZE;
 
        host = mmc_priv(mmc);
        host->mmc = mmc;
@@ -460,8 +471,7 @@ static int pxamci_probe(struct device *dev)
        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->imask = MMC_I_MASK_ALL;
 
        host->base = ioremap(r->start, SZ_4K);
        if (!host->base) {
@@ -478,17 +488,14 @@ static int pxamci_probe(struct device *dev)
        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);
+       host->dma = pxa_request_dma(DRIVER_NAME, 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);
+       ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
        if (ret)
                goto out;
 
@@ -535,15 +542,14 @@ static int pxamci_remove(struct device *dev)
                       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
                       host->base + MMC_I_MASK);
 
-               pxa_set_cken(CKEN12_MMC, 0);
+               DRCMRRXMMC = 0;
+               DRCMRTXMMC = 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);
@@ -579,7 +585,7 @@ static int pxamci_resume(struct device *dev, u32 level)
 #endif
 
 static struct device_driver pxamci_driver = {
-       .name           = "pxa2xx-mci",
+       .name           = DRIVER_NAME,
        .bus            = &platform_bus_type,
        .probe          = pxamci_probe,
        .remove         = pxamci_remove,
index a80b24d..1b16322 100644 (file)
 #define BUF_PART_FULL          (1 << 0)
 
 #define MMC_I_MASK     0x0028
+
+/*PXA27x MMC interrupts*/
+#define SDIO_SUSPEND_ACK       (1 << 12)
+#define SDIO_INT               (1 << 11)
+#define RD_STALLED             (1 << 10)
+#define RES_ERR                (1 << 9)
+#define DAT_ERR                (1 << 8)
+#define TINT                   (1 << 7)
+
+/*PXA2xx MMC interrupts*/
 #define TXFIFO_WR_REQ          (1 << 6)
 #define RXFIFO_RD_REQ          (1 << 5)
 #define CLK_IS_OFF             (1 << 4)
 #define PRG_DONE               (1 << 1)
 #define DATA_TRAN_DONE         (1 << 0)
 
+#ifdef CONFIG_PXA27x
+#define MMC_I_MASK_ALL          0x00001fff
+#else
+#define MMC_I_MASK_ALL          0x0000007f
+#endif
+
 #define MMC_I_REG      0x002c
 /* same as MMC_I_MASK */
 
 #define MMC_RXFIFO     0x0040  /* 8 bit */
 
 #define MMC_TXFIFO     0x0044  /* 8 bit */
+
+/*
+ * The base MMC clock rate
+ */
+#ifdef CONFIG_PXA27x
+#define CLOCKRATE_MIN  304688
+#define CLOCKRATE_MAX  19500000
+#else
+#define CLOCKRATE_MIN  312500
+#define CLOCKRATE_MAX  20000000
+#endif
+
+#define CLOCKRATE      CLOCKRATE_MAX
+
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 */
index f9ff6f0..c6c8383 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Common code to handle absent "placeholder" devices
  * Copyright 2001 Resilience Corporation <ebrower@resilience.com>
- * $Id: map_absent.c,v 1.4 2003/05/28 12:51:49 dwmw2 Exp $
+ * $Id: map_absent.c,v 1.5 2004/11/16 18:29:00 dwmw2 Exp $
  *
  * This map driver is used to allocate "placeholder" MTD
  * devices on systems that have socketed/removable media. 
@@ -98,7 +98,7 @@ static void map_absent_destroy(struct mtd_info *mtd)
        /* nop */
 }
 
-int __init map_absent_init(void)
+static int __init map_absent_init(void)
 {
        register_mtd_chip_driver(&map_absent_chipdrv);
        return 0;
index 5fe0a08..aafe29b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * mtdram - a test mtd device
- * $Id: mtdram.c,v 1.33 2004/08/09 13:19:44 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.34 2004/11/16 18:29:01 dwmw2 Exp $
  * Author: Alexander Larsson <alex@cendio.se>
  *
  * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
@@ -153,7 +153,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
 
 #if CONFIG_MTDRAM_TOTAL_SIZE > 0
 #if CONFIG_MTDRAM_ABS_POS > 0
-int __init init_mtdram(void)
+static int __init init_mtdram(void)
 {
   void *addr;
   int err;
@@ -186,7 +186,7 @@ int __init init_mtdram(void)
 
 #else /* CONFIG_MTDRAM_ABS_POS > 0 */
 
-int __init init_mtdram(void)
+static int __init init_mtdram(void)
 {
   void *addr;
   int err;
@@ -220,7 +220,7 @@ int __init init_mtdram(void)
 
 #else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
 
-int __init init_mtdram(void)
+static int __init init_mtdram(void)
 {
   return 0;
 }
index 03a955c..8aab73e 100644 (file)
@@ -1,6 +1,6 @@
 /**
  *
- * $Id: phram.c,v 1.2 2004/08/09 13:19:44 dwmw2 Exp $
+ * $Id: phram.c,v 1.3 2004/11/16 18:29:01 dwmw2 Exp $
  *
  * Copyright (c) Jochen Schaeuble <psionic@psionic.de>
  * 07/2003     rewritten by Joern Engel <joern@wh.fh-wedel.de>
@@ -39,7 +39,7 @@ static LIST_HEAD(phram_list);
 
 
 
-int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
+static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
        u_char *start = (u_char *)mtd->priv;
 
@@ -60,7 +60,7 @@ int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
        return 0;
 }
 
-int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
+static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char **mtdbuf)
 {
        u_char *start = (u_char *)mtd->priv;
@@ -73,11 +73,11 @@ int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
        return 0;
 }
 
-void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
 }
 
-int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
+static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf)
 {
        u_char *start = (u_char *)mtd->priv;
@@ -91,7 +91,7 @@ int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
        return 0;
 }
 
-int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
+static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
                size_t *retlen, const u_char *buf)
 {
        u_char *start = (u_char *)mtd->priv;
@@ -340,7 +340,7 @@ module_param_call(slram, slram_setup, NULL, NULL, 000);
 MODULE_PARM_DESC(slram, "List of memory regions to map. \"map=<name>,<start><length/end>\"");
 
 
-int __init init_phram(void)
+static int __init init_phram(void)
 {
        printk(KERN_ERR "phram loaded\n");
        return 0;
index fd579ae..1caf00b 100644 (file)
@@ -1,6 +1,6 @@
 /*======================================================================
 
-  $Id: slram.c,v 1.31 2004/08/09 13:19:44 dwmw2 Exp $
+  $Id: slram.c,v 1.32 2004/11/16 18:29:01 dwmw2 Exp $
 
   This driver provides a method to access memory not used by the kernel
   itself (i.e. if the kernel commandline mem=xxx is used). To actually
@@ -75,13 +75,13 @@ MODULE_PARM_DESC(map, "List of memory regions to map. \"map=<name>, <start>, <le
 
 static slram_mtd_list_t *slram_mtdlist = NULL;
 
-int slram_erase(struct mtd_info *, struct erase_info *);
-int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
-void slram_unpoint(struct mtd_info *, u_char *, loff_t,        size_t);
-int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int slram_erase(struct mtd_info *, struct erase_info *);
+static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
+static void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
+static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 
-int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
+static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
        slram_priv_t *priv = mtd->priv;
 
@@ -103,7 +103,7 @@ int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
        return(0);
 }
 
-int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
+static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char **mtdbuf)
 {
        slram_priv_t *priv = (slram_priv_t *)mtd->priv;
@@ -113,11 +113,11 @@ int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
        return(0);
 }
 
-void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
 }
 
-int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
+static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf)
 {
        slram_priv_t *priv = (slram_priv_t *)mtd->priv;
@@ -128,7 +128,7 @@ int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
        return(0);
 }
 
-int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
+static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
                size_t *retlen, const u_char *buf)
 {
        slram_priv_t *priv = (slram_priv_t *)mtd->priv;
@@ -141,7 +141,7 @@ int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
 
 /*====================================================================*/
 
-int register_device(char *name, unsigned long start, unsigned long length)
+static int register_device(char *name, unsigned long start, unsigned long length)
 {
        slram_mtd_list_t **curmtd;
 
@@ -213,7 +213,7 @@ int register_device(char *name, unsigned long start, unsigned long length)
        return(0);      
 }
 
-void unregister_devices(void)
+static void unregister_devices(void)
 {
        slram_mtd_list_t *nextitem;
 
@@ -228,7 +228,7 @@ void unregister_devices(void)
        }
 }
 
-unsigned long handle_unit(unsigned long value, char *unit)
+static unsigned long handle_unit(unsigned long value, char *unit)
 {
        if ((*unit == 'M') || (*unit == 'm')) {
                return(value * 1024 * 1024);
@@ -238,7 +238,7 @@ unsigned long handle_unit(unsigned long value, char *unit)
        return(value);
 }
 
-int parse_cmdline(char *devname, char *szstart, char *szlength)
+static int parse_cmdline(char *devname, char *szstart, char *szlength)
 {
        char *buffer;
        unsigned long devstart;
@@ -285,7 +285,7 @@ __setup("slram=", mtd_slram_setup);
 
 #endif
 
-int init_slram(void)
+static int init_slram(void)
 {
        char *devname;
        int i;
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");
index b250404..d213888 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Flash memory access on Alchemy Db1550 board
  * 
- * $Id: db1550-flash.c,v 1.3 2004/07/14 17:45:40 dwmw2 Exp $
+ * $Id: db1550-flash.c,v 1.7 2004/11/04 13:24:14 gleixner Exp $
  *
  * (C) 2004 Embedded Edge, LLC, based on db1550-flash.c:
- * (C) 2003 Pete Popov <pete_popov@yahoo.com>
+ * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
  * 
  */
 
@@ -19,7 +19,6 @@
 #include <linux/mtd/partitions.h>
 
 #include <asm/io.h>
-#include <asm/au1000.h>
 
 #ifdef         DEBUG_RW
 #define        DBG(x...)       printk(x)
@@ -132,7 +131,7 @@ int setup_flash_params(void)
                        window_addr = 0x1C000000;
                        window_size = 0x4000000; 
 #else /* USER ONLY */
-                       window_addr = 0x1E000000;
+                       window_addr = 0x18000000;
                        window_size = 0x4000000; 
 #endif
        return 0;
@@ -160,10 +159,9 @@ int __init db1550_mtd_init(void)
         * Now let's probe for the actual flash.  Do it here since
         * specific machine settings might have been set above.
         */
-       printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n", 
+       printk(KERN_NOTICE "Db1550 flash: probing %d-bit flash bus\n", 
                        db1550_map.bankwidth*8);
-       db1550_map.virt = 
-               (unsigned long)ioremap(window_addr, window_size);
+       db1550_map.virt = ioremap(window_addr, window_size);
        mymtd = do_map_probe("cfi_probe", &db1550_map);
        if (!mymtd) return -ENXIO;
        mymtd->owner = THIS_MODULE;
@@ -177,6 +175,7 @@ static void __exit db1550_mtd_cleanup(void)
        if (mymtd) {
                del_mtd_partitions(mymtd);
                map_destroy(mymtd);
+               iounmap((void *) db1550_map.virt);
        }
 }
 
index 388e14b..faa68ec 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * Flash memory access on Alchemy Db1xxx boards
  * 
- * $Id: db1x00-flash.c,v 1.3 2004/07/14 17:45:40 dwmw2 Exp $
+ * $Id: db1x00-flash.c,v 1.6 2004/11/04 13:24:14 gleixner Exp $
  *
- * (C) 2003 Pete Popov <ppopov@pacbell.net>
+ * (C) 2003 Pete Popov <ppopov@embeddedalley.com>
  * 
  */
 
@@ -18,8 +18,6 @@
 #include <linux/mtd/partitions.h>
 
 #include <asm/io.h>
-#include <asm/au1000.h>
-#include <asm/db1x00.h>
 
 #ifdef         DEBUG_RW
 #define        DBG(x...)       printk(x)
 #define        DBG(x...)       
 #endif
 
+/* MTD CONFIG OPTIONS */
+#if defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
+#define DB1X00_BOTH_BANKS
+#elif defined(CONFIG_MTD_DB1X00_BOOT) && !defined(CONFIG_MTD_DB1X00_USER)
+#define DB1X00_BOOT_ONLY
+#elif !defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
+#define DB1X00_USER_ONLY
+#endif
+
 static unsigned long window_addr;
 static unsigned long window_size;
 static unsigned long flash_size;
 
-static BCSR * const bcsr = (BCSR *)0xAE000000;
+static unsigned short *bcsr = (unsigned short *)0xAE000000;
 static unsigned char flash_bankwidth = 4;
 
 /* 
@@ -113,7 +120,7 @@ static struct mtd_info *db1xxx_mtd;
  */
 int setup_flash_params(void)
 {
-       switch ((bcsr->status >> 14) & 0x3) {
+       switch ((bcsr[2] >> 14) & 0x3) {
                case 0: /* 64Mbit devices */
                        flash_size = 0x800000; /* 8MB per part */
 #if defined(DB1X00_BOTH_BANKS)
@@ -192,7 +199,7 @@ int __init db1x00_mtd_init(void)
         */
        printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n", 
                        db1xxx_mtd_map.bankwidth*8);
-       db1xxx_mtd_map.virt = (unsigned long)ioremap(window_addr, window_size);
+       db1xxx_mtd_map.virt = ioremap(window_addr, window_size);
        db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map);
        if (!db1xxx_mtd) return -ENXIO;
        db1xxx_mtd->owner = THIS_MODULE;
index cdb9c1b..b9bc635 100644 (file)
@@ -4,7 +4,7 @@
  * 
  * Flash map driver for the Dy4 SVME182 board
  * 
- * $Id: dmv182.c,v 1.3 2004/07/14 17:45:40 dwmw2 Exp $
+ * $Id: dmv182.c,v 1.5 2004/11/04 13:24:14 gleixner Exp $
  *
  * Copyright 2003-2004, TimeSys Corporation
  *
@@ -103,8 +103,7 @@ static int __init init_svme182(void)
 
        partitions = svme182_partitions;
 
-       svme182_map.virt = 
-               (unsigned long)ioremap(FLASH_BASE_ADDR, svme182_map.size);
+       svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size);
                
        if (svme182_map.virt == 0) {
                printk("Failed to ioremap FLASH memory area.\n");
index a26cc3a..9a8890d 100644 (file)
@@ -2,7 +2,7 @@
  * ichxrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: ichxrom.c,v 1.8 2004/07/16 17:43:11 dwmw2 Exp $
+ * $Id: ichxrom.c,v 1.15 2004/11/16 18:29:02 dwmw2 Exp $
  */
 
 #include <linux/module.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/flashchip.h>
 #include <linux/config.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
-#include <linux/mtd/cfi.h>
+#include <linux/list.h>
 
 #define xstr(s) str(s)
 #define str(s) #s
 #define MOD_NAME xstr(KBUILD_BASENAME)
 
-#define MTD_DEV_NAME_LENGTH 16
-
-#define RESERVE_MEM_REGION 0
-
+#define ADDRESS_NAME_LEN 18
 
-#define MANUFACTURER_INTEL     0x0089
-#define I82802AB       0x00ad
-#define I82802AC       0x00ac
+#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
 
-#define ICHX_FWH_REGION_START  0xFF000000UL
-#define ICHX_FWH_REGION_SIZE   0x01000000UL
 #define BIOS_CNTL      0x4e
 #define FWH_DEC_EN1    0xE3
 #define FWH_DEC_EN2    0xF0
 #define FWH_SEL1       0xE8
 #define FWH_SEL2       0xEE
 
-struct ichxrom_map_info {
-       struct map_info map;
-       struct mtd_info *mtd;
-       unsigned long window_addr;
+struct ichxrom_window {
+       void __iomem* virt;
+       unsigned long phys;
+       unsigned long size;
+       struct list_head maps;
+       struct resource rsrc;
        struct pci_dev *pdev;
-       struct resource window_rsrc;
-       struct resource rom_rsrc;
-       char mtd_name[MTD_DEV_NAME_LENGTH];
 };
 
-static inline unsigned long addr(struct map_info *map, unsigned long ofs)
-{
-       unsigned long offset;
-       offset = ((8*1024*1024) - map->size) + ofs;
-       if (offset >= (4*1024*1024)) {
-               offset += 0x400000;
-       }
-       return map->map_priv_1 + 0x400000 + offset;
-}
-
-static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr)
-{
-       return addr - map->map_priv_1 + ICHX_FWH_REGION_START;
-}
-       
-static map_word ichxrom_read(struct map_info *map, unsigned long ofs)
-{
-       map_word val;
-       int i;
-       switch(map->bankwidth) {
-       case 1:  val.x[0] = __raw_readb(addr(map, ofs)); break;
-       case 2:  val.x[0] = __raw_readw(addr(map, ofs)); break;
-       case 4:  val.x[0] = __raw_readl(addr(map, ofs)); break;
-#if BITS_PER_LONG >= 64
-       case 8:  val.x[0] = __raw_readq(addr(map, ofs)); break;
-#endif
-       default: val.x[0] = 0; break;
-       }
-       for(i = 1; i < map_words(map); i++) {
-               val.x[i] = 0;
-       }
-       return val;
-}
-
-static void ichxrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-       memcpy_fromio(to, addr(map, from), len);
-}
-
-static void ichxrom_write(struct map_info *map, map_word d, unsigned long ofs)
-{
-       switch(map->bankwidth) {
-       case 1: __raw_writeb(d.x[0], addr(map,ofs)); break;
-       case 2: __raw_writew(d.x[0], addr(map,ofs)); break;
-       case 4: __raw_writel(d.x[0], addr(map,ofs)); break;
-#if BITS_PER_LONG >= 64
-       case 8: __raw_writeq(d.x[0], addr(map,ofs)); break;
-#endif
-       }
-       mb();
-}
-
-static void ichxrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-       memcpy_toio(addr(map, to), from, len);
-}
-
-static struct ichxrom_map_info ichxrom_map = {
-       .map = {
-               .name = MOD_NAME,
-               .phys = NO_XIP,
-               .size = 0,
-               .bankwidth = 1,
-               .read = ichxrom_read,
-               .copy_from = ichxrom_copy_from,
-               .write = ichxrom_write,
-               .copy_to = ichxrom_copy_to,
-               /* Firmware hubs only use vpp when being programmed
-                * in a factory setting.  So in-place programming
-                * needs to use a different method.
-                */
-       },
-       /* remaining fields of structure are initialized to 0 */
+struct ichxrom_map_info {
+       struct list_head list;
+       struct map_info map;
+       struct mtd_info *mtd;
+       struct resource rsrc;
+       char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
 };
 
-enum fwh_lock_state {
-       FWH_DENY_WRITE = 1,
-       FWH_IMMUTABLE  = 2,
-       FWH_DENY_READ  = 4,
+static struct ichxrom_window ichxrom_window = {
+       .maps = LIST_HEAD_INIT(ichxrom_window.maps),
 };
 
-static void ichxrom_cleanup(struct ichxrom_map_info *info)
+static void ichxrom_cleanup(struct ichxrom_window *window)
 {
+       struct ichxrom_map_info *map, *scratch;
        u16 word;
 
        /* Disable writes through the rom window */
-       pci_read_config_word(info->pdev, BIOS_CNTL, &word);
-       pci_write_config_word(info->pdev, BIOS_CNTL, word & ~1);
-
-       if (info->mtd) {
-               del_mtd_device(info->mtd);
-               map_destroy(info->mtd);
-               info->mtd = NULL;
-               info->map.virt = 0;
+       pci_read_config_word(window->pdev, BIOS_CNTL, &word);
+       pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
+
+       /* Free all of the mtd devices */
+       list_for_each_entry_safe(map, scratch, &window->maps, list) {
+               if (map->rsrc.parent)
+                       release_resource(&map->rsrc);
+               del_mtd_device(map->mtd);
+               map_destroy(map->mtd);
+               list_del(&map->list);
+               kfree(map);
        }
-       if (info->rom_rsrc.parent)
-               release_resource(&info->rom_rsrc);
-       if (info->window_rsrc.parent)
-               release_resource(&info->window_rsrc);
-
-       if (info->window_addr) {
-               iounmap((void *)(info->window_addr));
-               info->window_addr = 0;
-       }
-}
-
-
-static int ichxrom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len,
-       enum fwh_lock_state state)
-{
-       struct map_info *map = mtd->priv;
-       unsigned long start = ofs;
-       unsigned long end = start + len -1;
-
-       /* FIXME do I need to guard against concurrency here? */
-       /* round down to 64K boundaries */
-       start = start & ~0xFFFF;
-       end = end & ~0xFFFF;
-       while (start <= end) {
-               unsigned long ctrl_addr;
-               ctrl_addr = addr(map, start) - 0x400000 + 2;
-               writeb(state, ctrl_addr);
-               start = start + 0x10000;
+       if (window->rsrc.parent)
+               release_resource(&window->rsrc);
+       if (window->virt) {
+               iounmap(window->virt);
+               window->virt = NULL;
+               window->phys = 0;
+               window->size = 0;
+               window->pdev = NULL;
        }
-       return 0;
 }
 
-static int ichxrom_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-       return ichxrom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE);
-}
-
-static int ichxrom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-       return ichxrom_set_lock_state(mtd, ofs, len, 0);
-}
 
 static int __devinit ichxrom_init_one (struct pci_dev *pdev,
        const struct pci_device_id *ent)
 {
+       static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
+       struct ichxrom_window *window = &ichxrom_window;
+       struct ichxrom_map_info *map = NULL;
+       unsigned long map_top;
+       u8 byte;
        u16 word;
-       struct ichxrom_map_info *info = &ichxrom_map;
-       unsigned long map_size;
-       static char *probes[] = { "cfi_probe", "jedec_probe" };
-       struct cfi_private *cfi;
 
        /* For now I just handle the ichx and I assume there
         * are not a lot of resources up at the top of the address
@@ -204,26 +104,56 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
         * Also you can page firmware hubs if an 8MB window isn't enough 
         * but don't currently handle that case either.
         */
+       window->pdev = pdev;
+
+       /* Find a region continuous to the end of the ROM window  */
+       window->phys = 0;
+       pci_read_config_byte(pdev, FWH_DEC_EN1, &byte);
+       if (byte == 0xff) {
+               window->phys = 0xffc00000;
+               pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
+               if ((byte & 0x0f) == 0x0f) {
+                       window->phys = 0xff400000;
+               }
+               else if ((byte & 0x0e) == 0x0e) {
+                       window->phys = 0xff500000;
+               }
+               else if ((byte & 0x0c) == 0x0c) {
+                       window->phys = 0xff600000;
+               }
+               else if ((byte & 0x08) == 0x08) {
+                       window->phys = 0xff700000;
+               }
+       }
+       else if ((byte & 0xfe) == 0xfe) {
+               window->phys = 0xffc80000;
+       }
+       else if ((byte & 0xfc) == 0xfc) {
+               window->phys = 0xffd00000;
+       }
+       else if ((byte & 0xf8) == 0xf8) {
+               window->phys = 0xffd80000;
+       }
+       else if ((byte & 0xf0) == 0xf0) {
+               window->phys = 0xffe00000;
+       }
+       else if ((byte & 0xe0) == 0xe0) {
+               window->phys = 0xffe80000;
+       }
+       else if ((byte & 0xc0) == 0xc0) {
+               window->phys = 0xfff00000;
+       }
+       else if ((byte & 0x80) == 0x80) {
+               window->phys = 0xfff80000; 
+       }
 
-       info->pdev = pdev;
-
-       /*
-        * Try to reserve the window mem region.  If this fails then
-        * it is likely due to the window being "reseved" by the BIOS.
-        */
-       info->window_rsrc.name = MOD_NAME;
-       info->window_rsrc.start = ICHX_FWH_REGION_START;
-       info->window_rsrc.end = ICHX_FWH_REGION_START + ICHX_FWH_REGION_SIZE - 1;
-       info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-       if (request_resource(&iomem_resource, &info->window_rsrc)) {
-               info->window_rsrc.parent = NULL;
-               printk(KERN_ERR MOD_NAME
-                      " %s(): Unable to register resource"
-                      " 0x%.08lx-0x%.08lx - kernel bug?\n",
-                      __func__,
-                      info->window_rsrc.start, info->window_rsrc.end);
+       if (window->phys == 0) {
+               printk(KERN_ERR MOD_NAME ": Rom window is closed\n");
+               goto out;
        }
-       
+       window->phys -= 0x400000UL;
+       window->size = (0xffffffffUL - window->phys) + 1UL;
+
        /* Enable writes through the rom window */
        pci_read_config_word(pdev, BIOS_CNTL, &word);
        if (!(word & 1)  && (word & (1<<1))) {
@@ -231,119 +161,167 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
                 * this device, so don't even try.
                 */
                printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
-               goto failed;
+               goto out;
        }
        pci_write_config_word(pdev, BIOS_CNTL, word | 1);
 
+       /*
+        * Try to reserve the window mem region.  If this fails then
+        * it is likely due to the window being "reseved" by the BIOS.
+        */
+       window->rsrc.name = MOD_NAME;
+       window->rsrc.start = window->phys;
+       window->rsrc.end   = window->phys + window->size - 1;
+       window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+       if (request_resource(&iomem_resource, &window->rsrc)) {
+               window->rsrc.parent = NULL;
+               printk(KERN_DEBUG MOD_NAME
+                       ": %s(): Unable to register resource"
+                       " 0x%.08lx-0x%.08lx - kernel bug?\n",
+                       __func__,
+                       window->rsrc.start, window->rsrc.end);
+       }
 
        /* Map the firmware hub into my address space. */
-       /* Does this use too much virtual address space? */
-       info->window_addr = (unsigned long)ioremap(
-               ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE);
-       if (!info->window_addr) {
-               printk(KERN_ERR "Failed to ioremap\n");
-               goto failed;
+       window->virt = ioremap_nocache(window->phys, window->size);
+       if (!window->virt) {
+               printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
+                       window->phys, window->size);
+               goto out;
        }
 
-       /* For now assume the firmware has setup all relevant firmware
-        * windows.  We don't have enough information to handle this case
-        * intelligently.
+       /* Get the first address to look for an rom chip at */
+       map_top = window->phys;
+       if ((window->phys & 0x3fffff) != 0) {
+               map_top = window->phys + 0x400000;
+       }
+#if 1
+       /* The probe sequence run over the firmware hub lock
+        * registers sets them to 0x7 (no access).
+        * Probe at most the last 4M of the address space.
         */
+       if (map_top < 0xffc00000) {
+               map_top = 0xffc00000;
+       }
+#endif
+       /* Loop through and look for rom chips */
+       while((map_top - 1) < 0xffffffffUL) {
+               struct cfi_private *cfi;
+               unsigned long offset;
+               int i;
+
+               if (!map) {
+                       map = kmalloc(sizeof(*map), GFP_KERNEL);
+               }
+               if (!map) {
+                       printk(KERN_ERR MOD_NAME ": kmalloc failed");
+                       goto out;
+               }
+               memset(map, 0, sizeof(*map));
+               INIT_LIST_HEAD(&map->list);
+               map->map.name = map->map_name;
+               map->map.phys = map_top;
+               offset = map_top - window->phys;
+               map->map.virt = (void __iomem *)
+                       (((unsigned long)(window->virt)) + offset);
+               map->map.size = 0xffffffffUL - map_top + 1UL;
+               /* Set the name of the map to the address I am trying */
+               sprintf(map->map_name, "%s @%08lx",
+                       MOD_NAME, map->map.phys);
 
-       /* FIXME select the firmware hub and enable a window to it. */
-
-       info->mtd = NULL;
-       info->map.map_priv_1 = info->window_addr;
-
-       /* Loop through the possible bankwidths */
-       for(ichxrom_map.map.bankwidth = 4; ichxrom_map.map.bankwidth; ichxrom_map.map.bankwidth >>= 1) {
-               map_size = ICHX_FWH_REGION_SIZE;
-               while(!info->mtd && (map_size > 0)) {
-                       int i;
-                       info->map.size = map_size;
-                       for(i = 0; i < sizeof(probes)/sizeof(char *); i++) {
-                               info->mtd = do_map_probe(probes[i], &ichxrom_map.map);
-                               if (info->mtd)
-                                       break;
+               /* Firmware hubs only use vpp when being programmed
+                * in a factory setting.  So in-place programming
+                * needs to use a different method.
+                */
+               for(map->map.bankwidth = 32; map->map.bankwidth; 
+                       map->map.bankwidth >>= 1)
+               {
+                       char **probe_type;
+                       /* Skip bankwidths that are not supported */
+                       if (!map_bankwidth_supported(map->map.bankwidth))
+                               continue;
+
+                       /* Setup the map methods */
+                       simple_map_init(&map->map);
+
+                       /* Try all of the probe methods */
+                       probe_type = rom_probe_types;
+                       for(; *probe_type; probe_type++) {
+                               map->mtd = do_map_probe(*probe_type, &map->map);
+                               if (map->mtd)
+                                       goto found;
                        }
-                       map_size -= 512*1024;
                }
-               if (info->mtd)
-                       break;
-       }
-       if (!info->mtd) {
-               goto failed;
-       }
-       cfi = ichxrom_map.map.fldrv_priv;
-       if ((cfi->mfr == MANUFACTURER_INTEL) && (
-                   (cfi->id == I82802AB) ||
-                   (cfi->id == I82802AC))) 
-       {
-               /* If it is a firmware hub put in the special lock
-                * and unlock routines.
-                */
-               info->mtd->lock = ichxrom_lock;
-               info->mtd->unlock = ichxrom_unlock;
-       }
-       if (info->mtd->size > info->map.size) {
-               printk(KERN_WARNING MOD_NAME " rom(%u) larger than window(%lu). fixing...\n",
-                      info->mtd->size, info->map.size);
-               info->mtd->size = info->map.size;
-       }
+               map_top += ROM_PROBE_STEP_SIZE;
+               continue;
+       found:
+               /* Trim the size if we are larger than the map */
+               if (map->mtd->size > map->map.size) {
+                       printk(KERN_WARNING MOD_NAME
+                               " rom(%u) larger than window(%lu). fixing...\n",
+                               map->mtd->size, map->map.size);
+                       map->mtd->size = map->map.size;
+               }
+               if (window->rsrc.parent) {
+                       /*
+                        * Registering the MTD device in iomem may not be possible
+                        * if there is a BIOS "reserved" and BUSY range.  If this
+                        * fails then continue anyway.
+                        */
+                       map->rsrc.name  = map->map_name;
+                       map->rsrc.start = map->map.phys;
+                       map->rsrc.end   = map->map.phys + map->mtd->size - 1;
+                       map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+                       if (request_resource(&window->rsrc, &map->rsrc)) {
+                               printk(KERN_ERR MOD_NAME
+                                       ": cannot reserve MTD resource\n");
+                               map->rsrc.parent = NULL;
+                       }
+               }
+
+               /* Make the whole region visible in the map */
+               map->map.virt = window->virt;
+               map->map.phys = window->phys;
+               cfi = map->map.fldrv_priv;
+               for(i = 0; i < cfi->numchips; i++) {
+                       cfi->chips[i].start += offset;
+               }
                
-       info->mtd->owner = THIS_MODULE;
-       add_mtd_device(info->mtd);
-
-       if (info->window_rsrc.parent) {
-               /*
-                * Registering the MTD device in iomem may not be possible
-                * if there is a BIOS "reserved" and BUSY range.  If this
-                * fails then continue anyway.
-                */
-               snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH,
-                        "mtd%d", info->mtd->index);
-
-               info->rom_rsrc.name = info->mtd_name;
-               info->rom_rsrc.start = ICHX_FWH_REGION_START
-                       + ICHX_FWH_REGION_SIZE - map_size;
-               info->rom_rsrc.end = ICHX_FWH_REGION_START
-                       + ICHX_FWH_REGION_SIZE;
-               info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-               if (request_resource(&info->window_rsrc, &info->rom_rsrc)) {
-                       printk(KERN_ERR MOD_NAME
-                              ": cannot reserve MTD resource\n");
-                       info->rom_rsrc.parent = NULL;
+               /* Now that the mtd devices is complete claim and export it */
+               map->mtd->owner = THIS_MODULE;
+               if (add_mtd_device(map->mtd)) {
+                       map_destroy(map->mtd);
+                       map->mtd = NULL;
+                       goto out;
                }
+
+
+               /* Calculate the new value of map_top */
+               map_top += map->mtd->size;
+
+               /* File away the map structure */
+               list_add(&map->list, &window->maps);
+               map = NULL;
        }
 
+ out:
+       /* Free any left over map structures */
+       if (map) {
+               kfree(map);
+       }
+       /* See if I have any map structures */
+       if (list_empty(&window->maps)) {
+               ichxrom_cleanup(window);
+               return -ENODEV;
+       }
        return 0;
-
- failed:
-       ichxrom_cleanup(info);
-       return -ENODEV;
 }
 
 
 static void __devexit ichxrom_remove_one (struct pci_dev *pdev)
 {
-       struct ichxrom_map_info *info = &ichxrom_map;
-       u16 word;
-
-       del_mtd_device(info->mtd);
-       map_destroy(info->mtd);
-       info->mtd = NULL;
-       info->map.map_priv_1 = 0;
-
-       iounmap((void *)(info->window_addr));
-       info->window_addr = 0;
-
-       /* Disable writes through the rom window */
-       pci_read_config_word(pdev, BIOS_CNTL, &word);
-       pci_write_config_word(pdev, BIOS_CNTL, word & ~1);
-
-#if RESERVE_MEM_REGION 
-       release_mem_region(ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE);
-#endif
+       struct ichxrom_window *window = &ichxrom_window;
+       ichxrom_cleanup(window);
 }
 
 static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
@@ -371,8 +349,7 @@ static struct pci_driver ichxrom_driver = {
 };
 #endif
 
-static struct pci_dev *mydev;
-int __init init_ichxrom(void)
+static int __init init_ichxrom(void)
 {
        struct pci_dev *pdev;
        struct pci_device_id *id;
@@ -385,7 +362,6 @@ int __init init_ichxrom(void)
                }
        }
        if (pdev) {
-               mydev = pdev;
                return ichxrom_init_one(pdev, &ichxrom_pci_tbl[0]);
        }
        return -ENXIO;
@@ -396,7 +372,7 @@ int __init init_ichxrom(void)
 
 static void __exit cleanup_ichxrom(void)
 {
-       ichxrom_remove_one(mydev);
+       ichxrom_remove_one(ichxrom_window.pdev);
 }
 
 module_init(init_ichxrom);
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");
index 104488c..c5b5f44 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ixp2000.c,v 1.1 2004/09/02 00:13:41 dsaxena Exp $
+ * $Id: ixp2000.c,v 1.5 2004/11/16 17:15:48 dsaxena Exp $
  *
  * drivers/mtd/maps/ixp2000.c
  *
@@ -14,7 +14,7 @@
  * 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>
@@ -44,8 +44,8 @@ struct ixp2000_flash_info {
 };
 
 static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
-{
-       unsigned long (*set_bank)(unsigned long) =
+{      
+       unsigned long (*set_bank)(unsigned long) = 
                (unsigned long(*)(unsigned long))map->map_priv_2;
 
        return (set_bank ? set_bank(ofs) : ofs);
@@ -53,15 +53,15 @@ static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long
 
 #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.
+ * 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, erratum 44.
  */
-static int errata44_workaround = 0;
+static int erratum44_workaround = 0;
 
 static inline unsigned long address_fix8_write(unsigned long addr)
 {
-       if (errata44_workaround) {
+       if (erratum44_workaround) {
                return (addr ^ 3);
        }
        return addr;
@@ -88,7 +88,7 @@ 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--)
+       while(len--) 
                *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++);
 }
 
@@ -127,8 +127,8 @@ static int ixp2000_flash_remove(struct device *_dev)
        if (info->map.map_priv_1)
                iounmap((void *) info->map.map_priv_1);
 
-       if (info->partitions)
-               kfree(info->partitions);
+       if (info->partitions) {
+               kfree(info->partitions); }
 
        if (info->res) {
                release_resource(info->res);
@@ -147,11 +147,11 @@ 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 flash_platform_data *plat; 
        struct ixp2000_flash_info *info;
        unsigned long window_size;
        int err = -1;
-
+       
        if (!ixp_data)
                return -ENODEV;
 
@@ -160,7 +160,7 @@ static int ixp2000_flash_probe(struct device *_dev)
                return -ENODEV;
 
        window_size = dev->resource->end - dev->resource->start + 1;
-       dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dM)\n",
+       dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", 
                        ixp_data->nr_banks, ((u32)window_size >> 20));
 
        if (plat->width != 1) {
@@ -173,7 +173,7 @@ static int ixp2000_flash_probe(struct device *_dev)
        if(!info) {
                err = -ENOMEM;
                goto Error;
-       }
+       }       
        memzero(info, sizeof(struct ixp2000_flash_info));
 
        dev_set_drvdata(&dev->dev, info);
@@ -183,7 +183,7 @@ static int ixp2000_flash_probe(struct device *_dev)
         * 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;
@@ -191,7 +191,7 @@ static int ixp2000_flash_probe(struct device *_dev)
        /*
         * 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.map_priv_2 = (void __iomem *) ixp_data->bank_setup;
 
        info->map.name = dev->dev.bus_id;
        info->map.read = ixp2000_flash_read8;
@@ -199,8 +199,8 @@ static int ixp2000_flash_probe(struct device *_dev)
        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,
+       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");
@@ -208,9 +208,8 @@ static int ixp2000_flash_probe(struct device *_dev)
                goto Error;
        }
 
-       info->map.map_priv_1 =
-           (unsigned long) ioremap(dev->resource->start,
-                                   dev->resource->end - dev->resource->start + 1);
+       info->map.map_priv_1 = 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;
@@ -224,12 +223,12 @@ static int ixp2000_flash_probe(struct device *_dev)
 
 #if defined(__ARMEB__)
        /*
-        * Enable errata 44 workaround for NPUs with broken slowport
+        * Enable erratum 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");
+       erratum44_workaround = ixp2000_has_broken_slowport();
+       dev_info(_dev, "Erratum 44 workaround %s\n",
+              erratum44_workaround ? "enabled" : "disabled");
 #endif
 
        info->mtd = do_map_probe(plat->map_name, &info->map);
index 1770b1a..5afe660 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ixp4xx.c,v 1.6 2004/09/17 00:25:06 gleixner Exp $
+ * $Id: ixp4xx.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $
  *
  * drivers/mtd/maps/ixp4xx.c
  *
@@ -69,7 +69,7 @@ static void ixp4xx_copy_from(struct map_info *map, void *to,
                dest[len - 1] = BYTE0(src[i]);
 }
 
-/*
+/* 
  * Unaligned writes are ignored, causing the 8-bit
  * probe to fail and proceed to the 16-bit probe (which succeeds).
  */
@@ -79,7 +79,7 @@ static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long
               *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
 }
 
-/*
+/* 
  * Fast write16 function without the probing check above
  */
 static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
@@ -196,9 +196,8 @@ static int ixp4xx_flash_probe(struct device *_dev)
                goto Error;
        }
 
-       info->map.map_priv_1 =
-           (void __iomem *) ioremap(dev->resource->start,
-                                   dev->resource->end - dev->resource->start + 1);
+       info->map.map_priv_1 = ioremap(dev->resource->start,
+                           dev->resource->end - dev->resource->start + 1);
        if (!info->map.map_priv_1) {
                printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n");
                err = -EIO;
@@ -212,7 +211,7 @@ static int ixp4xx_flash_probe(struct device *_dev)
                goto Error;
        }
        info->mtd->owner = THIS_MODULE;
-
+       
        /* Use the fast version */
        info->map.write = ixp4xx_write16,
 
index cc55200..4685e8e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Flash on MPC-1211
  *
- * $Id: mpc1211.c,v 1.3 2004/07/14 17:45:40 dwmw2 Exp $
+ * $Id: mpc1211.c,v 1.4 2004/09/16 23:27:13 gleixner Exp $
  *
  * (C) 2002 Interface, Saito.K & Jeanne
  *
@@ -44,7 +44,7 @@ static int __init init_mpc1211_maps(void)
        int nr_parts;
 
        mpc1211_flash_map.phys = 0;
-       mpc1211_flash_map.virt = P2SEGADDR(0);
+       mpc1211_flash_map.virt = (void __iomem *)P2SEGADDR(0);
 
        simple_map_init(&mpc1211_flash_map);
 
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");
index 4262f1c..4961090 100644 (file)
@@ -5,7 +5,7 @@
  *
  *  (C) 2002 MontVista Software, Inc.
  *
- * $Id: omap-toto-flash.c,v 1.2 2004/07/12 21:59:44 dwmw2 Exp $
+ * $Id: omap-toto-flash.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $
  */
 
 #include <linux/config.h>
@@ -35,7 +35,7 @@
 static struct map_info omap_toto_map_flash = {
        .name =         "OMAP Toto flash",
        .bankwidth =    2,
-       .virt =         OMAP_TOTO_FLASH_BASE,
+       .virt =         (void __iomem *)OMAP_TOTO_FLASH_BASE,
 };
 
  
index 4747fbc..1424726 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Flash memory access on Alchemy Pb1550 board
  * 
- * $Id: pb1550-flash.c,v 1.4 2004/07/14 17:45:40 dwmw2 Exp $
+ * $Id: pb1550-flash.c,v 1.6 2004/11/04 13:24:15 gleixner Exp $
  *
  * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c:
  * (C) 2003 Pete Popov <ppopov@pacbell.net>
@@ -178,8 +178,7 @@ int __init pb1550_mtd_init(void)
         */
        printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n", 
                        pb1550_map.bankwidth*8);
-       pb1550_map.virt = 
-               (unsigned long)ioremap(window_addr, window_size);
+       pb1550_map.virt = ioremap(window_addr, window_size);
        mymtd = do_map_probe("cfi_probe", &pb1550_map);
        if (!mymtd) return -ENXIO;
        mymtd->owner = THIS_MODULE;
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");
+
index cdd4ce1..0c830ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdblock_ro.c,v 1.18 2003/06/23 12:00:08 dwmw2 Exp $
+ * $Id: mtdblock_ro.c,v 1.19 2004/11/16 18:28:59 dwmw2 Exp $
  *
  * (C) 2003 David Woodhouse <dwmw2@infradead.org>
  *
@@ -58,7 +58,7 @@ static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
        kfree(dev);
 }
 
-struct mtd_blktrans_ops mtdblock_tr = {
+static struct mtd_blktrans_ops mtdblock_tr = {
        .name           = "mtdblock",
        .major          = 31,
        .part_bits      = 0,
index 8e4da65..4c7719c 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2004 Embedded Edge, LLC
  *
- * $Id: au1550nd.c,v 1.5 2004/05/17 07:19:35 ppopov Exp $
+ * $Id: au1550nd.c,v 1.11 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
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <asm/io.h>
+
+/* fixme: this is ugly */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
+#include <asm/mach-au1x00/au1000.h>
+#ifdef CONFIG_MIPS_PB1550
+#include <asm/mach-pb1x00/pb1550.h> 
+#endif
+#ifdef CONFIG_MIPS_DB1550
+#include <asm/mach-db1x00/db1x00.h> 
+#endif
+#else
 #include <asm/au1000.h>
 #ifdef CONFIG_MIPS_PB1550
 #include <asm/pb1550.h> 
 #ifdef CONFIG_MIPS_DB1550
 #include <asm/db1x00.h> 
 #endif
-
+#endif
 
 /*
  * MTD structure for NAND controller
  */
 static struct mtd_info *au1550_mtd = NULL;
-static volatile u32 p_nand;
-static int nand_width = 1; /* default, only x8 supported for now */
+static void __iomem *p_nand;
+static int nand_width = 1; /* default x8*/
 
-/* Internal buffers. Page buffer and oob buffer for one block*/
-static u_char data_buf[512 + 16];
-static u_char oob_buf[16 * 32];
+#define NAND_CS 1
 
 /*
  * Define partitions for flash device
@@ -70,183 +79,262 @@ const static struct mtd_partition partition_info[] = {
 #endif
 };
 
-static inline void write_cmd_reg(u8 cmd)
+
+/**
+ * au_read_byte -  read one byte from the chip
+ * @mtd:       MTD device structure
+ *
+ *  read function for 8bit buswith
+ */
+static u_char au_read_byte(struct mtd_info *mtd)
 {
-       if (nand_width)
-               *((volatile u8 *)(p_nand + MEM_STNAND_CMD)) = cmd;
-       else
-               *((volatile u16 *)(p_nand + MEM_STNAND_CMD)) = cmd;
+       struct nand_chip *this = mtd->priv;
+       u_char ret = readb(this->IO_ADDR_R);
        au_sync();
+       return ret;
 }
 
-static inline void write_addr_reg(u8 addr)
+/**
+ * au_write_byte -  write one byte to the chip
+ * @mtd:       MTD device structure
+ * @byte:      pointer to data byte to write
+ *
+ *  write function for 8it buswith
+ */
+static void au_write_byte(struct mtd_info *mtd, u_char byte)
 {
-       if (nand_width)
-               *((volatile u8 *)(p_nand + MEM_STNAND_ADDR)) = addr;
-       else
-               *((volatile u16 *)(p_nand + MEM_STNAND_ADDR)) = addr;
+       struct nand_chip *this = mtd->priv;
+       writeb(byte, this->IO_ADDR_W);
        au_sync();
 }
 
-static inline void write_data_reg(u8 data)
+/**
+ * au_read_byte16 -  read one byte endianess aware from the chip
+ * @mtd:       MTD device structure
+ *
+ *  read function for 16bit buswith with 
+ * endianess conversion
+ */
+static u_char au_read_byte16(struct mtd_info *mtd)
 {
-       if (nand_width)
-               *((volatile u8 *)(p_nand + MEM_STNAND_DATA)) = data;
-       else
-               *((volatile u16 *)(p_nand + MEM_STNAND_DATA)) = data;
+       struct nand_chip *this = mtd->priv;
+       u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
        au_sync();
+       return ret;
 }
 
-static inline u32 read_data_reg(void)
+/**
+ * au_write_byte16 -  write one byte endianess aware to the chip
+ * @mtd:       MTD device structure
+ * @byte:      pointer to data byte to write
+ *
+ *  write function for 16bit buswith with
+ * endianess conversion
+ */
+static void au_write_byte16(struct mtd_info *mtd, u_char byte)
 {
-       u32 data;
-       if (nand_width) {
-               data = *((volatile u8 *)(p_nand + MEM_STNAND_DATA));
-               au_sync();
-       }
-       else {
-               data = *((volatile u16 *)(p_nand + MEM_STNAND_DATA));
-               au_sync();
-       }
-       return data;
+       struct nand_chip *this = mtd->priv;
+       writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
+       au_sync();
 }
 
-void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
+/**
+ * au_read_word -  read one word from the chip
+ * @mtd:       MTD device structure
+ *
+ *  read function for 16bit buswith without 
+ * endianess conversion
+ */
+static u16 au_read_word(struct mtd_info *mtd)
 {
+       struct nand_chip *this = mtd->priv;
+       u16 ret = readw(this->IO_ADDR_R);
+       au_sync();
+       return ret;
 }
 
-int au1550_device_ready(struct mtd_info *mtd)
+/**
+ * au_write_word -  write one word to the chip
+ * @mtd:       MTD device structure
+ * @word:      data word to write
+ *
+ *  write function for 16bit buswith without 
+ * endianess conversion
+ */
+static void au_write_word(struct mtd_info *mtd, u16 word)
 {
-       int ready;
-       ready = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0;
-       return ready;
+       struct nand_chip *this = mtd->priv;
+       writew(word, this->IO_ADDR_W);
+       au_sync();
 }
 
-static u_char au1550_nand_read_byte(struct mtd_info *mtd)
+/**
+ * au_write_buf -  write buffer to chip
+ * @mtd:       MTD device structure
+ * @buf:       data buffer
+ * @len:       number of bytes to write
+ *
+ *  write function for 8bit buswith
+ */
+static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
-       u_char ret;
-       ret = read_data_reg();
-       return ret;
-}
+       int i;
+       struct nand_chip *this = mtd->priv;
 
-static void au1550_nand_write_byte(struct mtd_info *mtd, u_char byte)
-{
-       write_data_reg((u8)byte);
+       for (i=0; i<len; i++) {
+               writeb(buf[i], this->IO_ADDR_W);
+               au_sync();
+       }
 }
 
-static void 
-au1550_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+/**
+ * au_read_buf -  read chip data into buffer 
+ * @mtd:       MTD device structure
+ * @buf:       buffer to store date
+ * @len:       number of bytes to read
+ *
+ *  read function for 8bit buswith
+ */
+static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
        int i;
+       struct nand_chip *this = mtd->priv;
 
-       for (i=0; i<len; i++)
-               write_data_reg(buf[i]);
+       for (i=0; i<len; i++) {
+               buf[i] = readb(this->IO_ADDR_R);
+               au_sync();      
+       }
 }
 
-static void 
-au1550_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+/**
+ * au_verify_buf -  Verify chip data against buffer 
+ * @mtd:       MTD device structure
+ * @buf:       buffer containing the data to compare
+ * @len:       number of bytes to compare
+ *
+ *  verify function for 8bit buswith
+ */
+static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
        int i;
+       struct nand_chip *this = mtd->priv;
+
+       for (i=0; i<len; i++) {
+               if (buf[i] != readb(this->IO_ADDR_R))
+                       return -EFAULT;
+               au_sync();
+       }
 
-       for (i=0; i<len; i++)
-               buf[i] = (u_char)read_data_reg();
+       return 0;
 }
 
-static int 
-au1550_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+/**
+ * au_write_buf16 -  write buffer to chip
+ * @mtd:       MTD device structure
+ * @buf:       data buffer
+ * @len:       number of bytes to write
+ *
+ *  write function for 16bit buswith
+ */
+static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
 {
        int i;
+       struct nand_chip *this = mtd->priv;
+       u16 *p = (u16 *) buf;
+       len >>= 1;
+       
+       for (i=0; i<len; i++) {
+               writew(p[i], this->IO_ADDR_W);
+               au_sync();
+       }
+               
+}
 
-       for (i=0; i<len; i++)
-               if (buf[i] != (u_char)read_data_reg())
-                       return -EFAULT;
+/**
+ * au_read_buf16 -  read chip data into buffer 
+ * @mtd:       MTD device structure
+ * @buf:       buffer to store date
+ * @len:       number of bytes to read
+ *
+ *  read function for 16bit buswith
+ */
+static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+       u16 *p = (u16 *) buf;
+       len >>= 1;
 
-       return 0;
+       for (i=0; i<len; i++) {
+               p[i] = readw(this->IO_ADDR_R);
+               au_sync();
+       }
 }
 
-static void au1550_nand_select_chip(struct mtd_info *mtd, int chip)
+/**
+ * au_verify_buf16 -  Verify chip data against buffer 
+ * @mtd:       MTD device structure
+ * @buf:       buffer containing the data to compare
+ * @len:       number of bytes to compare
+ *
+ *  verify function for 16bit buswith
+ */
+static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
 {
-       switch(chip) {
-       case -1:
-               /* deassert chip enable */
-               au_writel(au_readl(MEM_STNDCTL) & ~0x20 , MEM_STNDCTL);
-               break;
-       case 0:
-               /* assert (force assert) chip enable */
-               au_writel(au_readl(MEM_STNDCTL) | 0x20 , MEM_STNDCTL);
-               break;
+       int i;
+       struct nand_chip *this = mtd->priv;
+       u16 *p = (u16 *) buf;
+       len >>= 1;
 
-       default:
-               BUG();
+       for (i=0; i<len; i++) {
+               if (p[i] != readw(this->IO_ADDR_R))
+                       return -EFAULT;
+               au_sync();
        }
+       return 0;
 }
 
-static void au1550_nand_command (struct mtd_info *mtd, unsigned command, 
-               int column, int page_addr)
+
+static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
 {
        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;
-               }
-               write_cmd_reg(readcmd);
-       }
-       write_cmd_reg(command);
-
-       if (column != -1 || page_addr != -1) {
-
-               /* Serially input address */
-               if (column != -1)
-                       write_addr_reg(column);
-               if (page_addr != -1) {
-                       write_addr_reg((unsigned char) (page_addr & 0xff));
-                       write_addr_reg(((page_addr >> 8) & 0xff));
-                       /* One more address cycle for higher density devices */
-                       if (mtd->size & 0x0c000000) 
-                               write_addr_reg((unsigned char) ((page_addr >> 16) & 0x0f));
-               }
-       }
-       
-       switch (command) {
-                       
-       case NAND_CMD_PAGEPROG:
-       case NAND_CMD_ERASE1:
-       case NAND_CMD_ERASE2:
-       case NAND_CMD_SEQIN:
-       case NAND_CMD_STATUS:
+       switch(cmd){
+
+       case NAND_CTL_SETCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; break;
+       case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break;
+
+       case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break;
+       case NAND_CTL_CLRALE: 
+               this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; 
+               /* FIXME: Nobody knows why this is neccecary, 
+                * but it works only that way */
+               udelay(1); 
                break;
 
-       case NAND_CMD_RESET:
-               if (this->dev_ready)    
-                       break;
-               udelay(this->chip_delay);
-               write_cmd_reg(NAND_CMD_STATUS);
-               while ( !(read_data_reg() & 0x40));
-               return;
-
-       /* This applies to read commands */     
-       default:
-               udelay (this->chip_delay);
+       case NAND_CTL_SETNCE: 
+               /* assert (force assert) chip enable */
+               au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break;
+               break;
+
+       case NAND_CTL_CLRNCE: 
+               /* deassert chip enable */
+               au_writel(0, MEM_STNDCTL); break;
+               break;
        }
+
+       this->IO_ADDR_R = this->IO_ADDR_W;
        
-       /* wait until command is processed */
-       while (!this->dev_ready(mtd));
+       /* Drain the writebuffer */
+       au_sync();
 }
 
+int au1550_device_ready(struct mtd_info *mtd)
+{
+       int ret = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0;
+       au_sync();
+       return ret;
+}
 
 /*
  * Main initialization routine
@@ -255,7 +343,7 @@ int __init au1550_init (void)
 {
        struct nand_chip *this;
        u16 boot_swapboot = 0; /* default value */
-       u32 mem_time;
+       int retval;
 
        /* Allocate memory for MTD device structure and private data */
        au1550_mtd = kmalloc (sizeof(struct mtd_info) + 
@@ -275,11 +363,9 @@ int __init au1550_init (void)
        /* Link the private data with the MTD structure */
        au1550_mtd->priv = this;
 
-       /* disable interrupts */
-       au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL);
 
-       /* disable NAND boot */
-       au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL);
+       /* MEM_STNDCTL: disable ints, disable nand boot */
+       au_writel(0, MEM_STNDCTL);
 
 #ifdef CONFIG_MIPS_PB1550
        /* set gpio206 high */
@@ -295,7 +381,6 @@ int __init au1550_init (void)
                case 0xD:
                        /* x16 NAND Flash */
                        nand_width = 0;
-                       printk("Pb1550 NAND: 16-bit NAND not supported by MTD\n");
                        break;
                case 1:
                case 9:
@@ -307,62 +392,62 @@ int __init au1550_init (void)
                        break;
                default:
                        printk("Pb1550 NAND: bad boot:swap\n");
-                       kfree(au1550_mtd);
-                       return 1;
+                       retval = -EINVAL;
+                       goto outmem;
        }
+#endif
 
        /* Configure RCE1 - should be done by YAMON */
-       au_writel(0x5 | (nand_width << 22), MEM_STCFG1);
-       au_writel(NAND_TIMING, MEM_STTIME1);
-       mem_time = au_readl(MEM_STTIME1);
+       au_writel(0x5 | (nand_width << 22), 0xB4001010); /* MEM_STCFG1 */
+       au_writel(NAND_TIMING, 0xB4001014); /* MEM_STTIME1 */
        au_sync();
 
-       /* setup and enable chip select */
+       /* setup and enable chip select, MEM_STADDR1 */
        /* we really need to decode offsets only up till 0x20 */
        au_writel((1<<28) | (NAND_PHYS_ADDR>>4) | 
                        (((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18), 
                        MEM_STADDR1);
        au_sync();
-#endif
 
-#ifdef CONFIG_MIPS_DB1550
-       /* Configure RCE1 - should be done by YAMON */
-       au_writel(0x00400005, MEM_STCFG1);
-       au_writel(0x00007774, MEM_STTIME1);
-       au_writel(0x12000FFF, MEM_STADDR1);
-#endif
-
-       p_nand = (volatile struct nand_regs *)ioremap(NAND_PHYS_ADDR, 0x1000);
+       p_nand = ioremap(NAND_PHYS_ADDR, 0x1000);
 
        /* Set address of hardware control function */
        this->hwcontrol = au1550_hwcontrol;
        this->dev_ready = au1550_device_ready;
        /* 30 us command delay time */
        this->chip_delay = 30;          
-
-       this->cmdfunc = au1550_nand_command;
-       this->select_chip = au1550_nand_select_chip;
-       this->write_byte = au1550_nand_write_byte;
-       this->read_byte = au1550_nand_read_byte;
-       this->write_buf = au1550_nand_write_buf;
-       this->read_buf = au1550_nand_read_buf;
-       this->verify_buf = au1550_nand_verify_buf;
        this->eccmode = NAND_ECC_SOFT;
 
-       /* Set internal data buffer */
-       this->data_buf = data_buf;
-       this->oob_buf = oob_buf;
+       this->options = NAND_NO_AUTOINCR;
+
+       if (!nand_width)
+               this->options |= NAND_BUSWIDTH_16;
+
+       this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte;
+       this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte;
+       this->write_word = au_write_word;
+       this->read_word = au_read_word;
+       this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf;
+       this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf;
+       this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf;
 
        /* Scan to find existence of the device */
        if (nand_scan (au1550_mtd, 1)) {
-               kfree (au1550_mtd);
-               return -ENXIO;
+               retval = -ENXIO;
+               goto outio;
        }
 
        /* Register the partitions */
        add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS);
 
        return 0;
+
+ outio:
+       iounmap ((void *)p_nand);
+       
+ outmem:
+       kfree (au1550_mtd);
+       return retval;
 }
 
 module_init(au1550_init);
@@ -375,16 +460,14 @@ static void __exit au1550_cleanup (void)
 {
        struct nand_chip *this = (struct nand_chip *) &au1550_mtd[1];
 
-       iounmap ((void *)p_nand);
-
-       /* Unregister partitions */
-       del_mtd_partitions(au1550_mtd);
-
-       /* Unregister the device */
-       del_mtd_device (au1550_mtd);
+       /* Release resources, unregister device */
+       nand_release (au1550_mtd);
 
        /* Free the MTD device structure */
        kfree (au1550_mtd);
+
+       /* Unmap */
+       iounmap ((void *)p_nand);
 }
 module_exit(au1550_cleanup);
 #endif
index 0f7dedd..f2116fa 100644 (file)
@@ -8,16 +8,22 @@
  * Author: David Woodhouse <dwmw2@infradead.org>
  * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
  * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
- *
+ * 
+ * Error correction code lifted from the old docecc code
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Copyright (C) 2000 Netgem S.A.
+ * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
+ *  
  * Interface to generic NAND code for M-Systems DiskOnChip devices
  *
- * $Id: diskonchip.c,v 1.34 2004/08/09 19:41:12 dbrown Exp $
+ * $Id: diskonchip.c,v 1.42 2004/11/16 18:29:03 dwmw2 Exp $
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
+#include <linux/rslib.h>
 #include <asm/io.h>
 
 #include <linux/mtd/mtd.h>
@@ -62,7 +68,7 @@ static unsigned long __initdata doc_locations[] = {
 static struct mtd_info *doclist = NULL;
 
 struct doc_priv {
-       unsigned long virtadr;
+       void __iomem *virtadr;
        unsigned long physadr;
        u_char ChipID;
        u_char CDSNControl;
@@ -96,28 +102,136 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd);
 static void doc200x_select_chip(struct mtd_info *mtd, int chip);
 
 static int debug=0;
-MODULE_PARM(debug, "i");
+module_param(debug, int, 0);
 
 static int try_dword=1;
-MODULE_PARM(try_dword, "i");
+module_param(try_dword, int, 0);
 
 static int no_ecc_failures=0;
-MODULE_PARM(no_ecc_failures, "i");
+module_param(no_ecc_failures, int, 0);
 
+#ifdef CONFIG_MTD_PARTITIONS
 static int no_autopart=0;
-MODULE_PARM(no_autopart, "i");
+module_param(no_autopart, int, 0);
+#endif
 
 #ifdef MTD_NAND_DISKONCHIP_BBTWRITE
 static int inftl_bbt_write=1;
 #else
 static int inftl_bbt_write=0;
 #endif
-MODULE_PARM(inftl_bbt_write, "i");
+module_param(inftl_bbt_write, int, 0);
 
 static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
-MODULE_PARM(doc_config_location, "l");
+module_param(doc_config_location, ulong, 0);
 MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
 
+
+/* Sector size for HW ECC */
+#define SECTOR_SIZE 512
+/* The sector bytes are packed into NB_DATA 10 bit words */
+#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
+/* Number of roots */
+#define NROOTS 4
+/* First consective root */
+#define FCR 510
+/* Number of symbols */
+#define NN 1023
+
+/* the Reed Solomon control structure */
+static struct rs_control *rs_decoder;
+
+/* 
+ * The HW decoder in the DoC ASIC's provides us a error syndrome,
+ * which we must convert to a standard syndrom usable by the generic
+ * Reed-Solomon library code.
+ *
+ * Fabrice Bellard figured this out in the old docecc code. I added
+ * some comments, improved a minor bit and converted it to make use
+ * of the generic Reed-Solomon libary. tglx
+ */
+static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
+{
+       int i, j, nerr, errpos[8];
+       uint8_t parity;
+       uint16_t ds[4], s[5], tmp, errval[8], syn[4];
+
+       /* Convert the ecc bytes into words */
+       ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
+       ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
+       ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
+       ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
+       parity = ecc[1];
+
+       /* Initialize the syndrom buffer */
+       for (i = 0; i < NROOTS; i++)
+               s[i] = ds[0];
+       /* 
+        *  Evaluate 
+        *  s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
+        *  where x = alpha^(FCR + i)
+        */
+       for(j = 1; j < NROOTS; j++) {
+               if(ds[j] == 0)
+                       continue;
+               tmp = rs->index_of[ds[j]];
+               for(i = 0; i < NROOTS; i++)
+                       s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];
+       }
+
+       /* Calc s[i] = s[i] / alpha^(v + i) */
+       for (i = 0; i < NROOTS; i++) {
+               if (syn[i])
+                       syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i));
+       }
+       /* Call the decoder library */
+       nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
+
+       /* Incorrectable errors ? */
+       if (nerr < 0)
+               return nerr;
+
+       /* 
+        * Correct the errors. The bitpositions are a bit of magic,
+        * but they are given by the design of the de/encoder circuit
+        * in the DoC ASIC's.
+        */
+       for(i = 0;i < nerr; i++) {
+               int index, bitpos, pos = 1015 - errpos[i];
+               uint8_t val;
+               if (pos >= NB_DATA && pos < 1019)
+                       continue;
+               if (pos < NB_DATA) {
+                       /* extract bit position (MSB first) */
+                       pos = 10 * (NB_DATA - 1 - pos) - 6;
+                       /* now correct the following 10 bits. At most two bytes
+                          can be modified since pos is even */
+                       index = (pos >> 3) ^ 1;
+                       bitpos = pos & 7;
+                       if ((index >= 0 && index < SECTOR_SIZE) || 
+                           index == (SECTOR_SIZE + 1)) {
+                               val = (uint8_t) (errval[i] >> (2 + bitpos));
+                               parity ^= val;
+                               if (index < SECTOR_SIZE)
+                                       data[index] ^= val;
+                       }
+                       index = ((pos >> 3) + 1) ^ 1;
+                       bitpos = (bitpos + 10) & 7;
+                       if (bitpos == 0)
+                               bitpos = 8;
+                       if ((index >= 0 && index < SECTOR_SIZE) || 
+                           index == (SECTOR_SIZE + 1)) {
+                               val = (uint8_t)(errval[i] << (8 - bitpos));
+                               parity ^= val;
+                               if (index < SECTOR_SIZE)
+                                       data[index] ^= val;
+                       }
+               }
+       }
+       /* If the parity is wrong, no rescue possible */
+       return parity ? -1 : nerr;
+}
+
 static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
 {
        volatile char dummy;
@@ -139,7 +253,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
 /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
 static int _DoC_WaitReady(struct doc_priv *doc)
 {
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        unsigned long timeo = jiffies + (HZ * 10);
 
        if(debug) printk("_DoC_WaitReady...\n");
@@ -169,7 +283,7 @@ static int _DoC_WaitReady(struct doc_priv *doc)
 
 static inline int DoC_WaitReady(struct doc_priv *doc)
 {
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int ret = 0;
 
        if (DoC_is_MillenniumPlus(doc)) {
@@ -195,7 +309,7 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
 
        if(debug)printk("write_byte %02x\n", datum);
        WriteDOC(datum, docptr, CDSNSlowIO);
@@ -206,7 +320,7 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        u_char ret;
 
        ReadDOC(docptr, CDSNSlowIO);
@@ -221,7 +335,7 @@ static void doc2000_writebuf(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
        if (debug)printk("writebuf of %d bytes: ", len);
        for (i=0; i < len; i++) {
@@ -237,7 +351,7 @@ static void doc2000_readbuf(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug)printk("readbuf of %d bytes: ", len);
@@ -252,7 +366,7 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug) printk("readbuf_dword of %d bytes: ", len);
@@ -273,7 +387,7 @@ static int doc2000_verifybuf(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        for (i=0; i < len; i++)
@@ -305,7 +419,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
                        uint32_t dword;
                        uint8_t byte[4];
                } ident;
-               unsigned long docptr = doc->virtadr;
+               void __iomem *docptr = doc->virtadr;
 
                doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
                doc2000_write_byte(mtd, NAND_CMD_READID);
@@ -364,7 +478,7 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
 
        WriteDOC(datum, docptr, CDSNSlowIO);
        WriteDOC(datum, docptr, Mil_CDSN_IO);
@@ -375,7 +489,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
 
        //ReadDOC(docptr, CDSNSlowIO);
        /* 11.4.5 -- delay twice to allow extended length cycle */
@@ -390,7 +504,7 @@ static void doc2001_writebuf(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        for (i=0; i < len; i++)
@@ -404,7 +518,7 @@ static void doc2001_readbuf(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        /* Start read pipeline */
@@ -422,7 +536,7 @@ static int doc2001_verifybuf(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        /* Start read pipeline */
@@ -442,7 +556,7 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        u_char ret;
 
         ReadDOC(docptr, Mplus_ReadPipeInit);
@@ -457,7 +571,7 @@ static void doc2001plus_writebuf(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug)printk("writebuf of %d bytes: ", len);
@@ -474,7 +588,7 @@ static void doc2001plus_readbuf(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug)printk("readbuf of %d bytes: ", len);
@@ -504,7 +618,7 @@ static int doc2001plus_verifybuf(struct mtd_info *mtd,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug)printk("verifybuf of %d bytes: ", len);
@@ -530,7 +644,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int floor = 0;
 
        if(debug)printk("select chip (%d)\n", chip);
@@ -556,7 +670,7 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int floor = 0;
 
        if(debug)printk("select chip (%d)\n", chip);
@@ -583,7 +697,7 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
 
        switch(cmd) {
        case NAND_CTL_SETNCE:
@@ -621,7 +735,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
 
        /*
         * Must terminate write pipeline before sending any commands
@@ -725,7 +839,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
 
        if (DoC_is_MillenniumPlus(doc)) {
                /* 11.4.2 -- must NOP four times before checking FR/B# */
@@ -763,7 +877,7 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
 
        /* Prime the ECC engine */
        switch(mode) {
@@ -782,7 +896,7 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
 
        /* Prime the ECC engine */
        switch(mode) {
@@ -803,7 +917,7 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int i;
        int emptymatch = 1;
 
@@ -861,7 +975,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
        int i, ret = 0;
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        volatile u_char dummy;
        int emptymatch = 1;
        
@@ -914,7 +1028,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
                   erased block, in which case the ECC will not come out right.
                   We'll suppress the error and tell the caller everything's
                   OK.  Because it is. */
-               if (!emptymatch) ret = doc_decode_ecc (dat, calc_ecc);
+               if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc);
                if (ret > 0)
                        printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
        }       
@@ -1385,13 +1499,13 @@ static inline int __init doc_probe(unsigned long physadr)
        struct mtd_info *mtd;
        struct nand_chip *nand;
        struct doc_priv *doc;
-       unsigned long virtadr;
+       void __iomem *virtadr;
        unsigned char save_control;
        unsigned char tmp, tmpb, tmpc;
        int reg, len, numchips;
        int ret = 0;
 
-       virtadr = (unsigned long)ioremap(physadr, DOC_IOREMAP_LEN);
+       virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
        if (!virtadr) {
                printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
                return -EIO;
@@ -1518,7 +1632,7 @@ static inline int __init doc_probe(unsigned long physadr)
              sizeof(struct nand_chip) +
              sizeof(struct doc_priv) +
              (2 * sizeof(struct nand_bbt_descr));
-       mtd = kmalloc(len, GFP_KERNEL);
+       mtd =  kmalloc(len, GFP_KERNEL);
        if (!mtd) {
                printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
                ret = -ENOMEM;
@@ -1543,7 +1657,7 @@ static inline int __init doc_probe(unsigned long physadr)
        nand->enable_hwecc      = doc200x_enable_hwecc;
        nand->calculate_ecc     = doc200x_calculate_ecc;
        nand->correct_data      = doc200x_correct_data;
-       //nand->data_buf
+
        nand->autooob           = &doc200x_oobinfo;
        nand->eccmode           = NAND_ECC_HW6_512;
        nand->options           = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
@@ -1589,13 +1703,47 @@ fail:
        return ret;
 }
 
-int __init init_nanddoc(void)
+static void release_nanddoc(void)
 {
-       int i;
+       struct mtd_info *mtd, *nextmtd;
+       struct nand_chip *nand;
+       struct doc_priv *doc;
+
+       for (mtd = doclist; mtd; mtd = nextmtd) {
+               nand = mtd->priv;
+               doc = (void *)nand->priv;
+
+               nextmtd = doc->nextdoc;
+               nand_release(mtd);
+               iounmap((void *)doc->virtadr);
+               kfree(mtd);
+       }
+}
+
+static int __init init_nanddoc(void)
+{
+       int i, ret = 0;
+
+       /* 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 510
+        * primitve element to generate roots = 1
+        * generator polinomial degree = 4
+        */
+       rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
+       if (!rs_decoder) {
+               printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
+               return -ENOMEM;
+       }
 
        if (doc_config_location) {
                printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
-               return doc_probe(doc_config_location);
+               ret = doc_probe(doc_config_location);
+               if (ret < 0)
+                       goto outerr;
        } else {
                for (i=0; (doc_locations[i] != 0xffffffff); i++) {
                        doc_probe(doc_locations[i]);
@@ -1605,25 +1753,23 @@ int __init init_nanddoc(void)
           found, so the user knows we at least tried. */
        if (!doclist) {
                printk(KERN_INFO "No valid DiskOnChip devices found\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto outerr;
        }
        return 0;
+outerr:
+       free_rs(rs_decoder);
+       return ret;
 }
 
-void __exit cleanup_nanddoc(void)
+static void __exit cleanup_nanddoc(void)
 {
-       struct mtd_info *mtd, *nextmtd;
-       struct nand_chip *nand;
-       struct doc_priv *doc;
+       /* Cleanup the nand/DoC resources */
+       release_nanddoc();
 
-       for (mtd = doclist; mtd; mtd = nextmtd) {
-               nand = mtd->priv;
-               doc = (void *)nand->priv;
-
-               nextmtd = doc->nextdoc;
-               nand_release(mtd);
-               iounmap((void *)doc->virtadr);
-               kfree(mtd);
+       /* Free the reed solomon resources */
+       if (rs_decoder) {
+               free_rs(rs_decoder);
        }
 }
 
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");
index ff6adf4..181b952 100644 (file)
  *  
  *  05-19-2004  tglx: Basic support for Renesas AG-AND chips
  *
+ *  09-24-2004  tglx: add support for hardware controllers (e.g. ECC) shared
+ *             among multiple independend devices. Suggestions and initial patch
+ *             from Ben Dooks <ben-mtd@fluff.org>
+ *
  * Credits:
  *     David Woodhouse for adding multichip support  
  *     
@@ -37,7 +41,7 @@
  *     The AG-AND chips have nice features for speed improvement,
  *     which are not supported yet. Read / program 4 pages in one go.
  *
- * $Id: nand_base.c,v 1.115 2004/08/09 13:19:45 dwmw2 Exp $
+ * $Id: nand_base.c,v 1.121 2004/10/06 19:53:11 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
@@ -131,25 +135,31 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
 #define nand_verify_pages(...) (0)
 #endif
                
-static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state);
+static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state);
 
 /**
- * nand_release_chip - [GENERIC] release chip
+ * nand_release_device - [GENERIC] release chip
  * @mtd:       MTD device structure
  * 
  * Deselect, release chip lock and wake up anyone waiting on the device 
  */
-static void nand_release_chip (struct mtd_info *mtd)
+static void nand_release_device (struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
 
        /* De-select the NAND device */
        this->select_chip(mtd, -1);
+       /* Do we have a hardware controller ? */
+       if (this->controller) {
+               spin_lock(&this->controller->lock);
+               this->controller->active = NULL;
+               spin_unlock(&this->controller->lock);
+       }
        /* Release the chip */
-       spin_lock_bh (&this->chip_lock);
+       spin_lock (&this->chip_lock);
        this->state = FL_READY;
        wake_up (&this->wq);
-       spin_unlock_bh (&this->chip_lock);
+       spin_unlock (&this->chip_lock);
 }
 
 /**
@@ -388,7 +398,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
                chipnr = (int)(ofs >> this->chip_shift);
 
                /* Grab the lock and see if the device is available */
-               nand_get_chip (this, mtd, FL_READING);
+               nand_get_device (this, mtd, FL_READING);
 
                /* Select the NAND device */
                this->select_chip(mtd, chipnr);
@@ -410,7 +420,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
                
        if (getchip) {
                /* Deselect and wake up anyone waiting on the device */
-               nand_release_chip(mtd);
+               nand_release_device(mtd);
        }       
        
        return res;
@@ -533,8 +543,8 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
                if (page_addr != -1) {
                        this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
                        this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
-                       /* One more address cycle for higher density devices */
-                       if (this->chipsize & 0x0c000000) 
+                       /* One more address cycle for devices > 32MiB */
+                       if (this->chipsize > (32 << 20))
                                this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
                }
                /* Latch in address */
@@ -689,15 +699,16 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
 }
 
 /**
- * nand_get_chip - [GENERIC] Get chip for selected access
+ * nand_get_device - [GENERIC] Get chip for selected access
  * @this:      the nand chip descriptor
  * @mtd:       MTD device structure
  * @new_state: the state which is requested 
  *
  * Get the device and lock it for exclusive access
  */
-static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state)
+static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
 {
+       struct nand_chip *active = this;
 
        DECLARE_WAITQUEUE (wait, current);
 
@@ -705,19 +716,29 @@ static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new
         * Grab the lock and see if the device is available 
        */
 retry:
-       spin_lock_bh (&this->chip_lock);
-
-       if (this->state == FL_READY) {
-               this->state = new_state;
-               spin_unlock_bh (&this->chip_lock);
-               return;
+       /* Hardware controller shared among independend devices */
+       if (this->controller) {
+               spin_lock (&this->controller->lock);
+               if (this->controller->active)
+                       active = this->controller->active;
+               else
+                       this->controller->active = this;
+               spin_unlock (&this->controller->lock);
        }
-
+       
+       if (active == this) {
+               spin_lock (&this->chip_lock);
+               if (this->state == FL_READY) {
+                       this->state = new_state;
+                       spin_unlock (&this->chip_lock);
+                       return;
+               }
+       }       
        set_current_state (TASK_UNINTERRUPTIBLE);
-       add_wait_queue (&this->wq, &wait);
-       spin_unlock_bh (&this->chip_lock);
+       add_wait_queue (&active->wq, &wait);
+       spin_unlock (&active->chip_lock);
        schedule ();
-       remove_wait_queue (&this->wq, &wait);
+       remove_wait_queue (&active->wq, &wait);
        goto retry;
 }
 
@@ -747,7 +768,6 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
         * any case on any machine. */
        ndelay (100);
 
-       spin_lock_bh (&this->chip_lock);
        if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
                this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1);
        else    
@@ -755,24 +775,19 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
 
        while (time_before(jiffies, timeo)) {           
                /* Check, if we were interrupted */
-               if (this->state != state) {
-                       spin_unlock_bh (&this->chip_lock);
+               if (this->state != state)
                        return 0;
-               }
+
                if (this->dev_ready) {
                        if (this->dev_ready(mtd))
+                               break;  
+               } else {
+                       if (this->read_byte(mtd) & NAND_STATUS_READY)
                                break;
                }
-               if (this->read_byte(mtd) & NAND_STATUS_READY)
-                       break;
-                                               
-               spin_unlock_bh (&this->chip_lock);
                yield ();
-               spin_lock_bh (&this->chip_lock);
        }
        status = (int) this->read_byte(mtd);
-       spin_unlock_bh (&this->chip_lock);
-
        return status;
 }
 
@@ -1051,7 +1066,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        }
 
        /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd ,FL_READING);
+       nand_get_device (this, mtd ,FL_READING);
 
        /* use userspace supplied oobinfo, if zero */
        if (oobsel == NULL)
@@ -1281,7 +1296,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        }
 
        /* Deselect and wake up anyone waiting on the device */
-       nand_release_chip(mtd);
+       nand_release_device(mtd);
 
        /*
         * Return success, if no ECC failures, else -EBADMSG
@@ -1328,7 +1343,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
        }
 
        /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd , FL_READING);
+       nand_get_device (this, mtd , FL_READING);
 
        /* Select the NAND device */
        this->select_chip(mtd, chipnr);
@@ -1379,7 +1394,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
        }
 
        /* Deselect and wake up anyone waiting on the device */
-       nand_release_chip(mtd);
+       nand_release_device(mtd);
 
        /* Return happy */
        *retlen = len;
@@ -1413,7 +1428,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
        }
 
        /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd , FL_READING);
+       nand_get_device (this, mtd , FL_READING);
 
        this->select_chip (mtd, chip);
        
@@ -1442,7 +1457,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
        }
 
        /* Deselect and wake up anyone waiting on the device */
-       nand_release_chip(mtd);
+       nand_release_device(mtd);
        return 0;
 }
 
@@ -1564,7 +1579,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
        }
 
        /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd, FL_WRITING);
+       nand_get_device (this, mtd, FL_WRITING);
 
        /* Calculate chipnr */
        chipnr = (int)(to >> this->chip_shift);
@@ -1669,7 +1684,7 @@ cmp:
 
 out:
        /* Deselect and wake up anyone waiting on the device */
-       nand_release_chip(mtd);
+       nand_release_device(mtd);
 
        return ret;
 }
@@ -1709,7 +1724,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t *
        }
 
        /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd, FL_WRITING);
+       nand_get_device (this, mtd, FL_WRITING);
 
        /* Select the NAND device */
        this->select_chip(mtd, chipnr);
@@ -1771,7 +1786,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t *
        ret = 0;
 out:
        /* Deselect and wake up anyone waiting on the device */
-       nand_release_chip(mtd);
+       nand_release_device(mtd);
 
        return ret;
 }
@@ -1838,7 +1853,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
        }
 
        /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd, FL_WRITING);
+       nand_get_device (this, mtd, FL_WRITING);
 
        /* Get the current chip-nr */
        chipnr = (int) (to >> this->chip_shift);
@@ -1952,7 +1967,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
        ret = 0;
 out:
        /* Deselect and wake up anyone waiting on the device */
-       nand_release_chip(mtd);
+       nand_release_device(mtd);
 
        *retlen = written;
        return ret;
@@ -2041,7 +2056,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
        instr->fail_addr = 0xffffffff;
 
        /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd, FL_ERASING);
+       nand_get_device (this, mtd, FL_ERASING);
 
        /* Shift to get first page */
        page = (int) (instr->addr >> this->page_shift);
@@ -2112,7 +2127,7 @@ erase_exit:
                mtd_erase_callback(instr);
 
        /* Deselect and wake up anyone waiting on the device */
-       nand_release_chip(mtd);
+       nand_release_device(mtd);
 
        /* Return more or less happy */
        return ret;
@@ -2127,43 +2142,13 @@ erase_exit:
 static void nand_sync (struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       DECLARE_WAITQUEUE (wait, current);
 
        DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
 
-retry:
-       /* Grab the spinlock */
-       spin_lock_bh (&this->chip_lock);
-
-       /* See what's going on */
-       switch (this->state) {
-       case FL_READY:
-       case FL_SYNCING:
-               this->state = FL_SYNCING;
-               spin_unlock_bh (&this->chip_lock);
-               break;
-
-       default:
-               /* Not an idle state */
-               add_wait_queue (&this->wq, &wait);
-               spin_unlock_bh (&this->chip_lock);
-               schedule ();
-
-               remove_wait_queue (&this->wq, &wait);
-               goto retry;
-       }
-
-       /* Lock the device */
-       spin_lock_bh (&this->chip_lock);
-
-       /* Set the device to be ready again */
-       if (this->state == FL_SYNCING) {
-               this->state = FL_READY;
-               wake_up (&this->wq);
-       }
-
-       /* Unlock the device */
-       spin_unlock_bh (&this->chip_lock);
+       /* Grab the lock and see if the device is available */
+       nand_get_device (this, mtd, FL_SYNCING);
+       /* Release it and go back */
+       nand_release_device (mtd);
 }
 
 
index 2642e11..77f08d1 100644 (file)
@@ -6,7 +6,7 @@
  *   
  *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
  *
- * $Id: nand_bbt.c,v 1.24 2004/06/28 08:25:35 gleixner Exp $
+ * $Id: nand_bbt.c,v 1.26 2004/10/05 13:50:20 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
@@ -114,6 +114,7 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
  * @num:       the number of bbt descriptors to read
  * @bits:      number of bits per block
  * @offs:      offset in the memory table
+ * @reserved_block_code:       Pattern to identify reserved blocks
  *
  * Read the bad block table starting from page.
  *
@@ -796,7 +797,7 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
 
        len = mtd->size >> (this->bbt_erase_shift + 2);
        /* Allocate memory (2bit per block) */
-       this->bbt = (uint8_t *) kmalloc (len, GFP_KERNEL);
+       this->bbt = kmalloc (len, GFP_KERNEL);
        if (!this->bbt) {
                printk (KERN_ERR "nand_scan_bbt: Out of memory\n");
                return -ENOMEM;
index 9c356a0..e510a83 100644 (file)
@@ -6,7 +6,7 @@
  *  Derived from drivers/mtd/nand/edb7312.c
  *
  *
- * $Id: ppchameleonevb.c,v 1.2 2004/05/05 22:09:54 gleixner Exp $
+ * $Id: ppchameleonevb.c,v 1.6 2004/11/05 16:07:16 kalev 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
@@ -64,22 +64,17 @@ static struct mtd_info *ppchameleonevb_mtd = NULL;
 /*
  * Module stuff
  */
-static int ppchameleon_fio_pbase       = CFG_NAND0_PADDR;
-static int ppchameleonevb_fio_pbase = CFG_NAND1_PADDR;
+static unsigned long ppchameleon_fio_pbase     = CFG_NAND0_PADDR;
+static unsigned long ppchameleonevb_fio_pbase = CFG_NAND1_PADDR;
 
 #ifdef MODULE
-MODULE_PARM(ppchameleon_fio_pbase, "i");
+module_param(ppchameleon_fio_pbase, ulong, 0);
+module_param(ppchameleonevb_fio_pbase, ulong, 0);
+#else
 __setup("ppchameleon_fio_pbase=",ppchameleon_fio_pbase);
-MODULE_PARM(ppchameleonevb_fio_pbase, "i");
 __setup("ppchameleonevb_fio_pbase=",ppchameleonevb_fio_pbase);
 #endif
 
-/* Internal buffers. Page buffer and oob buffer for one block */
-static u_char data_buf[2048 + 64];
-static u_char oob_buf[64 * 64];
-static u_char data_buf_evb[512 + 16];
-static u_char oob_buf_evb[16 * 32];
-
 #ifdef CONFIG_MTD_PARTITIONS
 /*
  * Define static partitions for flash devices
@@ -196,8 +191,8 @@ static int __init ppchameleonevb_init (void)
        const char *part_type = 0;
        int mtd_parts_nb = 0;
        struct mtd_partition *mtd_parts = 0;
-       int ppchameleon_fio_base;
-       int ppchameleonevb_fio_base;
+       void __iomem *ppchameleon_fio_base;
+       void __iomem *ppchameleonevb_fio_base;
 
 
        /*********************************
@@ -205,15 +200,14 @@ static int __init ppchameleonevb_init (void)
        *********************************/
        /* Allocate memory for MTD device structure and private data */
        ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) +
-                            sizeof(struct nand_chip),
-                            GFP_KERNEL);
+                                                     sizeof(struct nand_chip), GFP_KERNEL);
        if (!ppchameleon_mtd) {
                printk("Unable to allocate PPChameleon NAND MTD device structure.\n");
                return -ENOMEM;
        }
 
        /* map physical address */
-       ppchameleon_fio_base = (unsigned long)ioremap(ppchameleon_fio_pbase, SZ_4M);
+       ppchameleon_fio_base = ioremap(ppchameleon_fio_pbase, SZ_4M);
        if(!ppchameleon_fio_base) {
                printk("ioremap PPChameleon NAND flash failed\n");
                kfree(ppchameleon_mtd);
@@ -264,10 +258,6 @@ static int __init ppchameleonevb_init (void)
        /* ECC mode */
        this->eccmode = NAND_ECC_SOFT;
 
-       /* Set internal data buffer */
-       this->data_buf = data_buf;
-       this->oob_buf = oob_buf;
-
        /* Scan to find existence of the device (it could not be mounted) */
        if (nand_scan (ppchameleon_mtd, 1)) {
                iounmap((void *)ppchameleon_fio_base);
@@ -309,15 +299,14 @@ nand_evb_init:
        ****************************/
        /* Allocate memory for MTD device structure and private data */
        ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) +
-                            sizeof(struct nand_chip),
-                            GFP_KERNEL);
+                                                        sizeof(struct nand_chip), GFP_KERNEL);
        if (!ppchameleonevb_mtd) {
                printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
                return -ENOMEM;
        }
 
        /* map physical address */
-       ppchameleonevb_fio_base = (unsigned long)ioremap(ppchameleonevb_fio_pbase, SZ_4M);
+       ppchameleonevb_fio_base = ioremap(ppchameleonevb_fio_pbase, SZ_4M);
        if(!ppchameleonevb_fio_base) {
                printk("ioremap PPChameleonEVB NAND flash failed\n");
                kfree(ppchameleonevb_mtd);
@@ -349,7 +338,8 @@ nand_evb_init:
        out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0);
        out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF);
        /* enable output driver */
-       out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
+       out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | 
+                NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
 #ifdef USE_READY_BUSY_PIN
        /* three-state select */
        out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0xFFFFFFFC);
@@ -359,7 +349,6 @@ nand_evb_init:
        out_be32((volatile unsigned*)GPIO0_ISR1L, (in_be32((volatile unsigned*)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001);
 #endif
 
-
        /* insert callbacks */
        this->IO_ADDR_R = ppchameleonevb_fio_base;
        this->IO_ADDR_W = ppchameleonevb_fio_base;
@@ -372,10 +361,6 @@ nand_evb_init:
        /* ECC mode */
        this->eccmode = NAND_ECC_SOFT;
 
-       /* Set internal data buffer */
-       this->data_buf = data_buf_evb;
-       this->oob_buf = oob_buf_evb;
-
        /* Scan to find existence of the device */
        if (nand_scan (ppchameleonevb_mtd, 1)) {
                iounmap((void *)ppchameleonevb_fio_base);
@@ -412,15 +397,20 @@ module_init(ppchameleonevb_init);
  */
 static void __exit ppchameleonevb_cleanup (void)
 {
-       struct nand_chip *this = (struct nand_chip *) &ppchameleonevb_mtd[1];
-
-       /* Unregister the device */
-       del_mtd_device (ppchameleonevb_mtd);
+       struct nand_chip *this;
 
-       /* Free internal data buffer */
-       kfree (this->data_buf);
+       /* Release resources, unregister device(s) */
+       nand_release (ppchameleon_mtd);
+       nand_release (ppchameleonevb_mtd);
+       
+       /* Release iomaps */
+       this = (struct nand_chip *) &ppchameleon_mtd[1];
+       iounmap((void *) this->IO_ADDR_R;
+       this = (struct nand_chip *) &ppchameleonevb_mtd[1];
+       iounmap((void *) this->IO_ADDR_R;
 
        /* Free the MTD device structure */
+       kfree (ppchameleon_mtd);
        kfree (ppchameleonevb_mtd);
 }
 module_exit(ppchameleonevb_cleanup);
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");
index ecb9f3d..52c808f 100644 (file)
@@ -15,7 +15,7 @@
  *   This is a device driver for the NAND flash device found on the
  *   TI fido board. It supports 32MiB and 64MiB cards
  *
- * $Id: toto.c,v 1.2 2003/10/21 10:04:58 dwmw2 Exp $
+ * $Id: toto.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $
  */
 
 #include <linux/slab.h>
@@ -37,7 +37,7 @@
  */
 static struct mtd_info *toto_mtd = NULL;
 
-static int toto_io_base = OMAP_FLASH_1_BASE;
+static unsigned long toto_io_base = OMAP_FLASH_1_BASE;
 
 #define CONFIG_NAND_WORKAROUND 1
 
@@ -155,14 +155,6 @@ int __init toto_init (void)
                goto out_mtd;
        }
 
-       /* Allocate memory for internal data buffer */
-       this->data_buf = kmalloc (sizeof(u_char) * (toto_mtd->oobblock + toto_mtd->oobsize), GFP_KERNEL);
-       if (!this->data_buf) {
-               printk (KERN_WARNING "Unable to allocate NAND data buffer for toto.\n");
-               err = -ENOMEM;
-               goto out_mtd;
-       }
-
        /* Register the partitions */
        switch(toto_mtd->size){
                case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; 
@@ -194,16 +186,8 @@ module_init(toto_init);
  */
 static void __exit toto_cleanup (void)
 {
-       struct nand_chip *this = (struct nand_chip *) &toto_mtd[1];
-
-       /* Unregister partitions */
-       del_mtd_partitions(toto_mtd);
-       
-       /* Unregister the device */
-       del_mtd_device (toto_mtd);
-
-       /* Free internal data buffers */
-       kfree (this->data_buf);
+       /* Release resources, unregister device */
+       nand_release (toto_mtd);
 
        /* Free the MTD device structure */
        kfree (toto_mtd);
index 5f6a2f5..bba6888 100644 (file)
@@ -11,7 +11,7 @@
  * Derived from drivers/mtd/autcpu12.c
  *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
  *
- * $Id: tx4925ndfmc.c,v 1.3 2004/07/20 02:44:26 dwmw2 Exp $
+ * $Id: tx4925ndfmc.c,v 1.5 2004/10/05 13:50:20 gleixner Exp $
  *
  * Copyright (C) 2001 Toshiba Corporation 
  * 
@@ -340,8 +340,8 @@ int __init tx4925ndfmc_init (void)
        tx4925ndfmc_mtd->priv = this;
 
        /* Set address of NAND IO lines */
-       this->IO_ADDR_R = (unsigned long)&(tx4925_ndfmcptr->dtr);
-       this->IO_ADDR_W = (unsigned long)&(tx4925_ndfmcptr->dtr);
+       this->IO_ADDR_R = (void __iomem *)&(tx4925_ndfmcptr->dtr);
+       this->IO_ADDR_W = (void __iomem *)&(tx4925_ndfmcptr->dtr);
        this->hwcontrol = tx4925ndfmc_hwcontrol;
        this->enable_hwecc = tx4925ndfmc_enable_hwecc;
        this->calculate_ecc = tx4925ndfmc_readecc;
@@ -363,14 +363,6 @@ int __init tx4925ndfmc_init (void)
                goto out_ior;
        }
 
-       /* Allocate memory for internal data buffer */
-       this->data_buf = kmalloc (sizeof(u_char) * (tx4925ndfmc_mtd->oobblock + tx4925ndfmc_mtd->oobsize), GFP_KERNEL);
-       if (!this->data_buf) {
-               printk ("Unable to allocate NAND data buffer for RBTX4925.\n");
-               err = -ENOMEM;
-               goto out_ior;
-       }
-
        /* Register the partitions */
 #ifdef CONFIG_MTD_CMDLINE_PARTS
         {
@@ -391,14 +383,12 @@ int __init tx4925ndfmc_init (void)
                default: {
                        printk ("Unsupported SmartMedia device\n"); 
                        err = -ENXIO;
-                       goto out_buf;
+                       goto out_ior;
                }
        }
 #endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */
        goto out;
 
-out_buf:
-       kfree (this->data_buf);    
 out_ior:
 out:
        return err;
@@ -412,16 +402,8 @@ module_init(tx4925ndfmc_init);
 #ifdef MODULE
 static void __exit tx4925ndfmc_cleanup (void)
 {
-       struct nand_chip *this = (struct nand_chip *) &tx4925ndfmc_mtd[1];
-
-       /* Unregister partitions */
-       del_mtd_partitions(tx4925ndfmc_mtd);
-       
-       /* Unregister the device */
-       del_mtd_device (tx4925ndfmc_mtd);
-
-       /* Free internal data buffers */
-       kfree (this->data_buf);
+       /* Release resources, unregister device */
+       nand_release (tx4925ndfmc_mtd);
 
        /* Free the MTD device structure */
        kfree (tx4925ndfmc_mtd);
index f2375b2..df26e58 100644 (file)
@@ -10,7 +10,7 @@
  *
  * Based on spia.c by Steven J. Hill
  *
- * $Id: tx4938ndfmc.c,v 1.2 2004/03/27 19:55:53 gleixner Exp $
+ * $Id: tx4938ndfmc.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $
  *
  * Copyright (C) 2000-2001 Toshiba Corporation 
  *
@@ -365,14 +365,6 @@ int __init tx4938ndfmc_init (void)
                return -ENXIO;
        }
 
-       /* Allocate memory for internal data buffer */
-       this->data_buf = kmalloc (sizeof(u_char) * (tx4938ndfmc_mtd->oobblock + tx4938ndfmc_mtd->oobsize), GFP_KERNEL);
-       if (!this->data_buf) {
-               printk ("Unable to allocate NAND data buffer for TX4938.\n");
-               kfree (tx4938ndfmc_mtd);
-               return -ENOMEM;
-       }
-
        if (protected) {
                printk(KERN_INFO "TX4938 NDFMC: write protected.\n");
                tx4938ndfmc_mtd->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE);
@@ -401,19 +393,11 @@ module_init(tx4938ndfmc_init);
  */
 static void __exit tx4938ndfmc_cleanup (void)
 {
-       struct nand_chip *this = (struct nand_chip *) tx4938ndfmc_mtd->priv;
-
-       /* Unregister the device */
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-       del_mtd_partitions(tx4938ndfmc_mtd);
-#endif
-       del_mtd_device (tx4938ndfmc_mtd);
+       /* Release resources, unregister device */
+       nand_release (tx4938ndfmc_mtd);
 
        /* Free the MTD device structure */
        kfree (tx4938ndfmc_mtd);
-
-       /* Free internal data buffer */
-       kfree (this->data_buf);
 }
 module_exit(tx4938ndfmc_cleanup);
 
index bcdc0d6..7dca6e5 100644 (file)
@@ -72,9 +72,9 @@ static int max_interrupt_work = 20;
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/ethtool.h>
+#include <linux/bitops.h>
 
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
index 0e5aec0..18b027e 100644 (file)
@@ -14,7 +14,6 @@
  */
 #include <linux/crc32.h>
 #include <linux/delay.h>
-#include <linux/dio.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
+#include <linux/irq.h>
 /* Used for the temporal inet entries and routing */
 #include <linux/socket.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
+#ifdef CONFIG_HP300
+#include <asm/blinken.h>
+#endif
 
 #include "7990.h"
 
+#define WRITERAP(lp,x) out_be16(lp->base + LANCE_RAP, (x))
+#define WRITERDP(lp,x) out_be16(lp->base + LANCE_RDP, (x))
+#define READRDP(lp) in_be16(lp->base + LANCE_RDP)
+
+#if defined(CONFIG_HPLANCE) || defined(CONFIG_HPLANCE_MODULE)
+#include "hplance.h"
+
+#undef WRITERAP
+#undef WRITERDP
+#undef READRDP
+
+#if defined(CONFIG_MVME147_NET) || defined(CONFIG_MVME147_NET_MODULE)
+
 /* Lossage Factor Nine, Mr Sulu. */
-#define WRITERAP(x) (lp->writerap(lp,x))
-#define WRITERDP(x) (lp->writerdp(lp,x))
-#define READRDP() (lp->readrdp(lp))
-/* These used to be ll->rap = x, ll->rdp = x, and (ll->rdp). Sigh. 
- * If you want to switch them back then 
- * #define DECLARE_LL volatile struct lance_regs *ll = lp->ll
- */
-#define DECLARE_LL /* nothing to declare */
+#define WRITERAP(lp,x) (lp->writerap(lp,x))
+#define WRITERDP(lp,x) (lp->writerdp(lp,x))
+#define READRDP(lp) (lp->readrdp(lp))
+
+#else
+
+/* These inlines can be used if only CONFIG_HPLANCE is defined */
+static inline void WRITERAP(struct lance_private *lp, __u16 value)
+{
+       do {
+               out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value);
+       } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
+}
+
+static inline void WRITERDP(struct lance_private *lp, __u16 value)
+{
+       do {
+               out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value);
+       } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
+}
+
+static inline __u16 READRDP(struct lance_private *lp)
+{
+       __u16 value;
+       do {
+               value = in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP);
+       } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
+       return value;
+}
+
+#endif
+#endif /* CONFIG_HPLANCE || CONFIG_HPLANCE_MODULE */
 
 /* debugging output macros, various flavours */
 /* #define TEST_HITS */
@@ -79,19 +119,18 @@ static void load_csrs (struct lance_private *lp)
 {
         volatile struct lance_init_block *aib = lp->lance_init_block;
         int leptr;
-        DECLARE_LL;
 
         leptr = LANCE_ADDR (aib);
 
-        WRITERAP(LE_CSR1);                        /* load address of init block */
-        WRITERDP(leptr & 0xFFFF);
-        WRITERAP(LE_CSR2);
-        WRITERDP(leptr >> 16);
-        WRITERAP(LE_CSR3);
-        WRITERDP(lp->busmaster_regval);           /* set byteswap/ALEctrl/byte ctrl */
+        WRITERAP(lp, LE_CSR1);                    /* load address of init block */
+        WRITERDP(lp, leptr & 0xFFFF);
+        WRITERAP(lp, LE_CSR2);
+        WRITERDP(lp, leptr >> 16);
+        WRITERAP(lp, LE_CSR3);
+        WRITERDP(lp, lp->busmaster_regval);       /* set byteswap/ALEctrl/byte ctrl */
 
         /* Point back to csr0 */
-        WRITERAP(LE_CSR0);
+        WRITERAP(lp, LE_CSR0);
 }
 
 /* #define to 0 or 1 appropriately */
@@ -192,24 +231,23 @@ static void lance_init_ring (struct net_device *dev)
 static int init_restart_lance (struct lance_private *lp)
 {
         int i;
-        DECLARE_LL;
 
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_INIT);
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_INIT);
 
         /* Need a hook here for sunlance ledma stuff */
 
         /* Wait for the lance to complete initialization */
-        for (i = 0; (i < 100) && !(READRDP() & (LE_C0_ERR | LE_C0_IDON)); i++)
+        for (i = 0; (i < 100) && !(READRDP(lp) & (LE_C0_ERR | LE_C0_IDON)); i++)
                 barrier();
-        if ((i == 100) || (READRDP() & LE_C0_ERR)) {
-                printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP());
+        if ((i == 100) || (READRDP(lp) & LE_C0_ERR)) {
+                printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP(lp));
                 return -1;
         }
 
         /* Clear IDON by writing a "1", enable interrupts and start lance */
-        WRITERDP(LE_C0_IDON);
-        WRITERDP(LE_C0_INEA | LE_C0_STRT);
+        WRITERDP(lp, LE_C0_IDON);
+        WRITERDP(lp, LE_C0_INEA | LE_C0_STRT);
 
         return 0;
 }
@@ -218,11 +256,10 @@ static int lance_reset (struct net_device *dev)
 {
         struct lance_private *lp = netdev_priv(dev);
         int status;
-        DECLARE_LL;
     
         /* Stop the lance */
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_STOP);
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_STOP);
 
         load_csrs (lp);
         lance_init_ring (dev);
@@ -245,7 +282,6 @@ static int lance_rx (struct net_device *dev)
 #ifdef TEST_HITS
         int i;
 #endif
-        DECLARE_LL;
 
 #ifdef TEST_HITS
         printk ("[");
@@ -259,8 +295,10 @@ static int lance_rx (struct net_device *dev)
         }
         printk ("]");
 #endif
-    
-        WRITERDP(LE_C0_RINT | LE_C0_INEA);     /* ack Rx int, reenable ints */
+#ifdef CONFIG_HP300
+       blinken_leds(0x40, 0);
+#endif    
+        WRITERDP(lp, LE_C0_RINT | LE_C0_INEA);     /* ack Rx int, reenable ints */
         for (rd = &ib->brx_ring [lp->rx_new];     /* For each Rx ring we own... */
              !((bits = rd->rmd1_bits) & LE_R1_OWN);
              rd = &ib->brx_ring [lp->rx_new]) {
@@ -321,10 +359,12 @@ static int lance_tx (struct net_device *dev)
         volatile struct lance_tx_desc *td;
         int i, j;
         int status;
-        DECLARE_LL;
 
+#ifdef CONFIG_HP300
+       blinken_leds(0x80, 0);
+#endif
         /* csr0 is 2f3 */
-        WRITERDP(LE_C0_TINT | LE_C0_INEA);
+        WRITERDP(lp, LE_C0_TINT | LE_C0_INEA);
         /* csr0 is 73 */
 
         j = lp->tx_old;
@@ -349,8 +389,8 @@ static int lance_tx (struct net_device *dev)
                                         printk("%s: Carrier Lost, trying %s\n",
                                                dev->name, lp->tpe?"TPE":"AUI");
                                         /* Stop the lance */
-                                        WRITERAP(LE_CSR0);
-                                        WRITERDP(LE_C0_STOP);
+                                        WRITERAP(lp, LE_CSR0);
+                                        WRITERDP(lp, LE_C0_STOP);
                                         lance_init_ring (dev);
                                         load_csrs (lp);
                                         init_restart_lance (lp);
@@ -366,8 +406,8 @@ static int lance_tx (struct net_device *dev)
                                 printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
                                         dev->name);
                                 /* Stop the lance */
-                                WRITERAP(LE_CSR0);
-                                WRITERDP(LE_C0_STOP);
+                                WRITERAP(lp, LE_CSR0);
+                                WRITERDP(lp, LE_C0_STOP);
                                 lance_init_ring (dev);
                                 load_csrs (lp);
                                 init_restart_lance (lp);
@@ -393,7 +433,7 @@ static int lance_tx (struct net_device *dev)
                 j = (j + 1) & lp->tx_ring_mod_mask;
         }
         lp->tx_old = j;
-        WRITERDP(LE_C0_TINT | LE_C0_INEA);
+        WRITERDP(lp, LE_C0_TINT | LE_C0_INEA);
         return 0;
 }
 
@@ -403,26 +443,25 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
         struct net_device *dev = (struct net_device *)dev_id;
         struct lance_private *lp = netdev_priv(dev);
         int csr0;
-        DECLARE_LL;
 
        spin_lock (&lp->devlock);
 
-        WRITERAP(LE_CSR0);              /* LANCE Controller Status */
-        csr0 = READRDP();
+        WRITERAP(lp, LE_CSR0);              /* LANCE Controller Status */
+        csr0 = READRDP(lp);
 
         PRINT_RINGS();
         
         if (!(csr0 & LE_C0_INTR)) {     /* Check if any interrupt has */
-               spin_lock (&lp->devlock);
+               spin_unlock (&lp->devlock);
                 return IRQ_NONE;        /* been generated by the Lance. */
        }
 
         /* Acknowledge all the interrupt sources ASAP */
-        WRITERDP(csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
+        WRITERDP(lp, csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
 
         if ((csr0 & LE_C0_ERR)) {
                 /* Clear the error condition */
-                WRITERDP(LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
+                WRITERDP(lp, LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
         }
 
         if (csr0 & LE_C0_RINT)
@@ -440,7 +479,7 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
                 printk("%s: Bus master arbitration failure, status %4.4x.\n", 
                        dev->name, csr0);
                 /* Restart the chip. */
-                WRITERDP(LE_C0_STRT);
+                WRITERDP(lp, LE_C0_STRT);
         }
 
         if (lp->tx_full && netif_queue_stopped(dev) && (TX_BUFFS_AVAIL >= 0)) {
@@ -448,8 +487,8 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
                netif_wake_queue (dev);
         }
         
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
 
        spin_unlock (&lp->devlock);
        return IRQ_HANDLED;
@@ -459,14 +498,13 @@ int lance_open (struct net_device *dev)
 {
         struct lance_private *lp = netdev_priv(dev);
        int res;
-        DECLARE_LL;
         
         /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
         if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
                 return -EAGAIN;
 
         res = lance_reset(dev);
-       lp->devlock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&lp->devlock);
        netif_start_queue (dev);
 
        return res;
@@ -475,13 +513,12 @@ int lance_open (struct net_device *dev)
 int lance_close (struct net_device *dev)
 {
         struct lance_private *lp = netdev_priv(dev);
-        DECLARE_LL;
         
        netif_stop_queue (dev);
 
         /* Stop the LANCE */
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_STOP);
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_STOP);
 
         free_irq(lp->irq, dev);
 
@@ -504,7 +541,6 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
         int entry, skblen, len;
         static int outs;
        unsigned long flags;
-        DECLARE_LL;
 
         if (!TX_BUFFS_AVAIL)
                 return -1;
@@ -540,7 +576,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
 
         outs++;
         /* Kick the lance: transmit now */
-        WRITERDP(LE_C0_INEA | LE_C0_TDMD);
+        WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD);
         dev->trans_start = jiffies;
         dev_kfree_skb (skb);
     
@@ -604,7 +640,6 @@ void lance_set_multicast (struct net_device *dev)
         struct lance_private *lp = netdev_priv(dev);
         volatile struct lance_init_block *ib = lp->init_block;
        int stopped;
-        DECLARE_LL;
 
        stopped = netif_queue_stopped(dev);
        if (!stopped)
@@ -613,8 +648,8 @@ void lance_set_multicast (struct net_device *dev)
         while (lp->tx_old != lp->tx_new)
                 schedule();
 
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_STOP);
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_STOP);
         lance_init_ring (dev);
 
         if (dev->flags & IFF_PROMISC) {
@@ -630,4 +665,17 @@ void lance_set_multicast (struct net_device *dev)
                netif_start_queue (dev);
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+void lance_poll(struct net_device *dev)
+{
+       struct lance_private *lp = netdev_priv(dev);
+
+       spin_lock (&lp->devlock);
+       WRITERAP(lp, LE_CSR0);
+       WRITERDP(lp, LE_C0_STRT);
+       spin_unlock (&lp->devlock);
+       lance_interrupt(dev->irq, dev, NULL);
+}
+#endif
+
 MODULE_LICENSE("GPL");
index 6875780..31ae509 100644 (file)
 #define _7990_H
 
 /* The lance only has two register locations. We communicate mostly via memory. */
-struct lance_regs 
-{
-        unsigned short rdp;                       /* Register Data Port */
-        unsigned short rap;                       /* Register Address Port */
-};
+#define LANCE_RDP      0       /* Register Data Port */
+#define LANCE_RAP      2       /* Register Address Port */
 
 /* Transmit/receive ring definitions.
  * We allow the specific drivers to override these defaults if they want to.
@@ -104,7 +101,7 @@ struct lance_init_block {
 struct lance_private
 {
         char *name;
-        volatile struct lance_regs *ll;
+       unsigned long base;
         volatile struct lance_init_block *init_block; /* CPU address of RAM */
         volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
         
@@ -252,5 +249,8 @@ extern int lance_start_xmit (struct sk_buff *skb, struct net_device *dev);
 extern struct net_device_stats *lance_get_stats (struct net_device *dev);
 extern void lance_set_multicast (struct net_device *dev);
 extern void lance_tx_timeout(struct net_device *dev);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+extern void lance_poll(struct net_device *dev);
+#endif
 
 #endif /* ndef _7990_H */
index 1b18b3a..a71423c 100644 (file)
@@ -71,6 +71,7 @@
 #include <linux/udp.h>
 #include <linux/cache.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/uaccess.h>
 
 /* VLAN tagging feature enable/disable */
@@ -335,7 +336,7 @@ struct cp_extra_stats {
 };
 
 struct cp_private {
-       void                    *regs;
+       void                    __iomem *regs;
        struct net_device       *dev;
        spinlock_t              lock;
        u32                     msg_enable;
@@ -366,7 +367,6 @@ struct cp_private {
 #endif
 
        unsigned int            wol_enabled : 1; /* Is Wake-on-LAN enabled? */
-       u32                     power_state[16];
 
        struct mii_if_info      mii_if;
 };
@@ -1580,11 +1580,11 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 #define EE_READ_CMD            (6)
 #define EE_ERASE_CMD   (7)
 
-static int read_eeprom (void *ioaddr, int location, int addr_len)
+static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
 {
        int i;
        unsigned retval = 0;
-       void *ee_addr = ioaddr + Cfg9346;
+       void __iomem *ee_addr = ioaddr + Cfg9346;
        int read_cmd = location | (EE_READ_CMD << addr_len);
 
        writeb (EE_ENB & ~EE_CS, ee_addr);
@@ -1631,7 +1631,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        struct net_device *dev;
        struct cp_private *cp;
        int rc;
-       void *regs;
+       void __iomem *regs;
        long pciaddr;
        unsigned int addr_len, i, pci_using_dac;
        u8 pci_rev;
@@ -1845,7 +1845,7 @@ static int cp_suspend (struct pci_dev *pdev, u32 state)
        spin_unlock_irqrestore (&cp->lock, flags);
 
        if (cp->pdev && cp->wol_enabled) {
-               pci_save_state (cp->pdev, cp->power_state);
+               pci_save_state (cp->pdev);
                cp_set_d3_state (cp);
        }
 
@@ -1864,7 +1864,7 @@ static int cp_resume (struct pci_dev *pdev)
        
        if (cp->pdev && cp->wol_enabled) {
                pci_set_power_state (cp->pdev, 0);
-               pci_restore_state (cp->pdev, cp->power_state);
+               pci_restore_state (cp->pdev);
        }
        
        cp_init_hw (cp);
index 04dcacd..e3053a8 100644 (file)
@@ -58,9 +58,9 @@ static const char version[] =
 #include <linux/fs.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/bitops.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <linux/delay.h>
@@ -813,7 +813,7 @@ static void ei_rx_overrun(struct net_device *dev)
         * We wait at least 10ms.
         */
 
-       udelay(10*1000);
+       mdelay(10);
 
        /*
         * Reset RBCR[01] back to zero as per magic incantation.
index 0d95f0b..8e538a6 100644 (file)
@@ -52,8 +52,8 @@
 #include <linux/init.h>
 #include <linux/crc32.h>
 #include <linux/zorro.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/irq.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
index 3fbfb7a..6d625d5 100644 (file)
@@ -23,7 +23,7 @@
 #define tigonFwRodata NULL
 #else
 /* Generated by genfw.c */
-static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
+static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
 0x10000003, 
 0x0, 0xd, 0xd, 0x3c1d0001, 
 0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000, 
index 91fa987..8918323 100755 (executable)
@@ -124,7 +124,7 @@ This function will read the PHY registers.
 */
 static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val)
 {
-       void mmio = lp->mmio;
+       void __iomem *mmio = lp->mmio;
        unsigned int reg_val;
        unsigned int repeat= REPEAT_CNT;
 
@@ -155,7 +155,7 @@ This function will write into PHY registers.
 static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val)
 {
        unsigned int repeat = REPEAT_CNT
-       void mmio = lp->mmio;
+       void __iomem *mmio = lp->mmio;
        unsigned int reg_val;
 
        reg_val = readl(mmio + PHY_ACCESS);
@@ -211,7 +211,7 @@ static void amd8111e_set_ext_phy(struct net_device *dev)
        u32 bmcr,advert,tmp;
        
        /* Determine mii register values to set the speed */
-       advert = amd8111e_mdio_read(dev, PHY_ID, MII_ADVERTISE);
+       advert = amd8111e_mdio_read(dev, lp->ext_phy_addr, MII_ADVERTISE);
        tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
        switch (lp->ext_phy_option){
 
@@ -235,11 +235,11 @@ static void amd8111e_set_ext_phy(struct net_device *dev)
        }
 
        if(advert != tmp)
-               amd8111e_mdio_write(dev, PHY_ID, MII_ADVERTISE, tmp);
+               amd8111e_mdio_write(dev, lp->ext_phy_addr, MII_ADVERTISE, tmp);
        /* Restart auto negotiation */
-       bmcr = amd8111e_mdio_read(dev, PHY_ID, MII_BMCR);
+       bmcr = amd8111e_mdio_read(dev, lp->ext_phy_addr, MII_BMCR);
        bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
-       amd8111e_mdio_write(dev, PHY_ID, MII_BMCR, bmcr);
+       amd8111e_mdio_write(dev, lp->ext_phy_addr, MII_BMCR, bmcr);
 
 }
 
@@ -350,6 +350,7 @@ static int amd8111e_init_ring(struct net_device *dev)
 
                lp->rx_ring[i].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[i]);
                lp->rx_ring[i].buff_count = cpu_to_le16(lp->rx_buff_len-2);
+               wmb();
                lp->rx_ring[i].rx_flags = cpu_to_le16(OWN_BIT);
        }
 
@@ -384,7 +385,7 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
        unsigned int event_count;
 
        struct amd8111e_priv *lp = netdev_priv(dev);
-       voidmmio = lp->mmio;
+       void __iomem *mmio = lp->mmio;
        struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf;
 
 
@@ -442,7 +443,7 @@ This function initializes the device registers  and starts the device.
 static int amd8111e_restart(struct net_device *dev)
 {
        struct amd8111e_priv *lp = netdev_priv(dev);
-       void mmio = lp->mmio;
+       void __iomem *mmio = lp->mmio;
        int i,reg_val;
 
        /* stop the chip */
@@ -522,14 +523,14 @@ static void amd8111e_init_hw_default( struct amd8111e_priv* lp)
 {
        unsigned int reg_val;
        unsigned int logic_filter[2] ={0,};
-       void mmio = lp->mmio;
+       void __iomem *mmio = lp->mmio;
 
 
         /* stop the chip */
        writel(RUN, mmio + CMD0);
 
        /* AUTOPOLL0 Register *//*TBD default value is 8100 in FPS */
-       writew( 0x8101, mmio + AUTOPOLL0);
+       writew( 0x8100 | lp->ext_phy_addr, mmio + AUTOPOLL0);
 
        /* Clear RCV_RING_BASE_ADDR */
        writel(0, mmio + RCV_RING_BASE_ADDR0);
@@ -723,9 +724,9 @@ static int amd8111e_tx(struct net_device *dev)
 /* This function handles the driver receive operation in polling mode */
 static int amd8111e_rx_poll(struct net_device *dev, int * budget)
 {
-       struct amd8111e_priv *lp = dev->priv;
+       struct amd8111e_priv *lp = netdev_priv(dev);
        int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;
-       void mmio = lp->mmio;
+       void __iomem *mmio = lp->mmio;
        struct sk_buff *skb,*new_skb;
        int min_pkt_len, status;
        unsigned int intr0;
@@ -740,11 +741,11 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
        do{   
                /* process receive packets until we use the quota*/
                /* If we own the next entry, it's a new packet. Send it up. */
-               while(!(lp->rx_ring[rx_index].rx_flags & OWN_BIT)){
-              
-                       /* check if err summary bit is set */ 
-                       if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags) 
-                                                               & ERR_BIT){
+               while(1) {
+                       status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
+                       if (status & OWN_BIT)
+                               break;
+
                        /* 
                         * There is a tricky error noted by John Murphy,
                         * <murf@perftech.com> to Russ Nelson: Even with
@@ -753,89 +754,88 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
                         * the last correctly noting the error.
                         */
 
-                       /* reseting flags */
-                       lp->rx_ring[rx_index].rx_flags &=RESET_RX_FLAGS;
-                       goto err_next_pkt;
-
+                       if(status & ERR_BIT) {
+                               /* reseting flags */
+                               lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+                               goto err_next_pkt;
                        }
                        /* check for STP and ENP */
-               status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
-               if(!((status & STP_BIT) && (status & ENP_BIT))){
-                       /* reseting flags */
-                       lp->rx_ring[rx_index].rx_flags &=RESET_RX_FLAGS;
-                       goto err_next_pkt;
-               }
-               pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
+                       if(!((status & STP_BIT) && (status & ENP_BIT))){
+                               /* reseting flags */
+                               lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+                               goto err_next_pkt;
+                       }
+                       pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
 
 #if AMD8111E_VLAN_TAG_USED             
-               vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK;
-               /*MAC will strip vlan tag*/ 
-               if(lp->vlgrp != NULL && vtag !=0)
-                       min_pkt_len =MIN_PKT_LEN - 4;
-               else
+                       vtag = status & TT_MASK;
+                       /*MAC will strip vlan tag*/ 
+                       if(lp->vlgrp != NULL && vtag !=0)
+                               min_pkt_len =MIN_PKT_LEN - 4;
+                       else
 #endif
-                       min_pkt_len =MIN_PKT_LEN;
+                               min_pkt_len =MIN_PKT_LEN;
 
-               if (pkt_len < min_pkt_len) {
-                       lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
-                       lp->drv_rx_errors++;
-                       goto err_next_pkt;
-               }
-               if(--rx_pkt_limit < 0)
-                       goto rx_not_empty;
-               if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
-                       /* if allocation fail, 
-                               ignore that pkt and go to next one */
-                       lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
-                       lp->drv_rx_errors++;
-                       goto err_next_pkt;
-               }
+                       if (pkt_len < min_pkt_len) {
+                               lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+                               lp->drv_rx_errors++;
+                               goto err_next_pkt;
+                       }
+                       if(--rx_pkt_limit < 0)
+                               goto rx_not_empty;
+                       if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
+                               /* if allocation fail, 
+                                  ignore that pkt and go to next one */
+                               lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
+                               lp->drv_rx_errors++;
+                               goto err_next_pkt;
+                       }
                
-               skb_reserve(new_skb, 2);
-               skb = lp->rx_skbuff[rx_index];
-               pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
-                       lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
-               skb_put(skb, pkt_len);
-               skb->dev = dev;
-               lp->rx_skbuff[rx_index] = new_skb;
-               new_skb->dev = dev;
-               lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,
-                       new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE);
-       
-               skb->protocol = eth_type_trans(skb, dev);
+                       skb_reserve(new_skb, 2);
+                       skb = lp->rx_skbuff[rx_index];
+                       pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
+                                        lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
+                       skb_put(skb, pkt_len);
+                       skb->dev = dev;
+                       lp->rx_skbuff[rx_index] = new_skb;
+                       new_skb->dev = dev;
+                       lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,
+                                                                  new_skb->data,
+                                                                  lp->rx_buff_len-2,
+                                                                  PCI_DMA_FROMDEVICE);
+       
+                       skb->protocol = eth_type_trans(skb, dev);
 
 #if AMD8111E_VLAN_TAG_USED             
-               
-               vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK;
-               if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
-                       amd8111e_vlan_rx(lp, skb,
-                                   lp->rx_ring[rx_index].tag_ctrl_info);
-               } else
+                       if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
+                               amd8111e_vlan_rx(lp, skb,
+                                        le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info));
+                       } else
 #endif
-                       
-                       netif_receive_skb(skb);
-               /*COAL update rx coalescing parameters*/
-               lp->coal_conf.rx_packets++;
-               lp->coal_conf.rx_bytes += pkt_len;      
-               num_rx_pkt++;
-               dev->last_rx = jiffies;
+                               netif_receive_skb(skb);
+                       /*COAL update rx coalescing parameters*/
+                       lp->coal_conf.rx_packets++;
+                       lp->coal_conf.rx_bytes += pkt_len;      
+                       num_rx_pkt++;
+                       dev->last_rx = jiffies;
        
-err_next_pkt:  
-               lp->rx_ring[rx_index].buff_phy_addr
-                        = cpu_to_le32(lp->rx_dma_addr[rx_index]);
-               lp->rx_ring[rx_index].buff_count = 
+               err_next_pkt:   
+                       lp->rx_ring[rx_index].buff_phy_addr
+                               = cpu_to_le32(lp->rx_dma_addr[rx_index]);
+                       lp->rx_ring[rx_index].buff_count = 
                                cpu_to_le16(lp->rx_buff_len-2);
-               lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
-               rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
-       }
-       /* Check the interrupt status register for more packets in the 
-       mean time. Process them since we have not used up our quota.*/
+                       wmb();
+                       lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
+                       rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
+               }
+               /* Check the interrupt status register for more packets in the 
+                  mean time. Process them since we have not used up our quota.*/
 
-       intr0 = readl(mmio + INT0);
-       /*Ack receive packets */
-       writel(intr0 & RINT0,mmio + INT0);
+               intr0 = readl(mmio + INT0);
+               /*Ack receive packets */
+               writel(intr0 & RINT0,mmio + INT0);
 
-       }while(intr0 & RINT0);
+       } while(intr0 & RINT0);
 
        /* Receive descriptor is empty now */
        dev->quota -= num_rx_pkt;
@@ -873,11 +873,12 @@ static int amd8111e_rx(struct net_device *dev)
        
        /* If we own the next entry, it's a new packet. Send it up. */
        while(++num_rx_pkt <= max_rx_pkt){
-               if(lp->rx_ring[rx_index].rx_flags & OWN_BIT)
+               status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
+               if(status & OWN_BIT)
                        return 0;
               
                /* check if err summary bit is set */ 
-               if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & ERR_BIT){
+               if(status & ERR_BIT){
                        /* 
                         * There is a tricky error noted by John Murphy,
                         * <murf@perftech.com> to Russ Nelson: Even with full-sized
@@ -888,7 +889,6 @@ static int amd8111e_rx(struct net_device *dev)
                        goto err_next_pkt;
                }
                /* check for STP and ENP */
-               status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
                if(!((status & STP_BIT) && (status & ENP_BIT))){
                        /* reseting flags */
                        lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
@@ -897,7 +897,7 @@ static int amd8111e_rx(struct net_device *dev)
                pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
 
 #if AMD8111E_VLAN_TAG_USED             
-               vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK;
+               vtag = status & TT_MASK;
                /*MAC will strip vlan tag*/ 
                if(lp->vlgrp != NULL && vtag !=0)
                        min_pkt_len =MIN_PKT_LEN - 4;
@@ -931,12 +931,10 @@ static int amd8111e_rx(struct net_device *dev)
        
                skb->protocol = eth_type_trans(skb, dev);
 
-#if AMD8111E_VLAN_TAG_USED             
-               
-               vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK;
+#if AMD8111E_VLAN_TAG_USED                             
                if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
                        amd8111e_vlan_rx(lp, skb,
-                                   lp->rx_ring[rx_index].tag_ctrl_info);
+                                le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info));
                } else
 #endif
                        
@@ -952,6 +950,7 @@ err_next_pkt:
                         = cpu_to_le32(lp->rx_dma_addr[rx_index]);
                lp->rx_ring[rx_index].buff_count = 
                                cpu_to_le16(lp->rx_buff_len-2);
+               wmb();
                lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
                rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
        }
@@ -1004,7 +1003,7 @@ static int amd8111e_link_change(struct net_device* dev)
 /*
 This function reads the mib counters.   
 */
-static int amd8111e_read_mib(voidmmio, u8 MIB_COUNTER)
+static int amd8111e_read_mib(void __iomem *mmio, u8 MIB_COUNTER)
 {
        unsigned int  status;
        unsigned  int data;
@@ -1027,7 +1026,7 @@ This function reads the mib registers and returns the hardware statistics. It  u
 static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
 {
        struct amd8111e_priv *lp = netdev_priv(dev);
-       void mmio = lp->mmio;
+       void __iomem *mmio = lp->mmio;
        unsigned long flags;
        /* struct net_device_stats *prev_stats = &lp->prev_stats; */
        struct net_device_stats* new_stats = &lp->stats;
@@ -1260,7 +1259,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg
 
        struct net_device * dev = (struct net_device *) dev_id;
        struct amd8111e_priv *lp = netdev_priv(dev);
-       void mmio = lp->mmio;
+       void __iomem *mmio = lp->mmio;
        unsigned int intr0;
        unsigned int handled = 1;
 
@@ -1432,7 +1431,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
 #if AMD8111E_VLAN_TAG_USED
        if((lp->vlgrp != NULL) && vlan_tx_tag_present(skb)){
                lp->tx_ring[tx_index].tag_ctrl_cmd |= 
-                               cpu_to_le32(TCC_VLAN_INSERT);   
+                               cpu_to_le16(TCC_VLAN_INSERT);   
                lp->tx_ring[tx_index].tag_ctrl_info = 
                                cpu_to_le16(vlan_tx_tag_get(skb));
 
@@ -1444,6 +1443,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
            (u32) cpu_to_le32(lp->tx_dma_addr[tx_index]);
 
        /*  Set FCS and LTINT bits */
+       wmb();
        lp->tx_ring[tx_index].tx_flags |=
            cpu_to_le16(OWN_BIT | STP_BIT | ENP_BIT|ADD_FCS_BIT|LTINT_BIT);
 
@@ -1464,32 +1464,25 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
 /*
 This function returns all the memory mapped registers of the device.
 */
-static char* amd8111e_read_regs(struct amd8111e_priv* lp)
-{      
-       void * mmio = lp->mmio;
-        u32 * reg_buff;
-
-       reg_buff = kmalloc( AMD8111E_REG_DUMP_LEN,GFP_KERNEL);
-       if(NULL == reg_buff)
-               return NULL;
-
+static void amd8111e_read_regs(struct amd8111e_priv *lp, u32 *buf)
+{
+       void __iomem *mmio = lp->mmio;
        /* Read only necessary registers */
-       reg_buff[0] = readl(mmio + XMT_RING_BASE_ADDR0);
-       reg_buff[1] = readl(mmio + XMT_RING_LEN0);
-       reg_buff[2] = readl(mmio + RCV_RING_BASE_ADDR0);
-       reg_buff[3] = readl(mmio + RCV_RING_LEN0);
-       reg_buff[4] = readl(mmio + CMD0);
-       reg_buff[5] = readl(mmio + CMD2);
-       reg_buff[6] = readl(mmio + CMD3);
-       reg_buff[7] = readl(mmio + CMD7);
-       reg_buff[8] = readl(mmio + INT0);
-       reg_buff[9] = readl(mmio + INTEN0);
-       reg_buff[10] = readl(mmio + LADRF);
-       reg_buff[11] = readl(mmio + LADRF+4);
-       reg_buff[12] = readl(mmio + STAT0);
-
-       return (char *)reg_buff;
+       buf[0] = readl(mmio + XMT_RING_BASE_ADDR0);
+       buf[1] = readl(mmio + XMT_RING_LEN0);
+       buf[2] = readl(mmio + RCV_RING_BASE_ADDR0);
+       buf[3] = readl(mmio + RCV_RING_LEN0);
+       buf[4] = readl(mmio + CMD0);
+       buf[5] = readl(mmio + CMD2);
+       buf[6] = readl(mmio + CMD3);
+       buf[7] = readl(mmio + CMD7);
+       buf[8] = readl(mmio + INT0);
+       buf[9] = readl(mmio + INTEN0);
+       buf[10] = readl(mmio + LADRF);
+       buf[11] = readl(mmio + LADRF+4);
+       buf[12] = readl(mmio + STAT0);
 }
+
 /*
 amd8111e crc generator implementation is different from the kernel
 ether_crc() function.
@@ -1567,131 +1560,101 @@ static void amd8111e_set_multicast_list(struct net_device *dev)
 
 }
 
-/*
-This function handles all the  ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application. 
-*/
-       
-static int amd8111e_ethtool_ioctl(struct net_device* dev, void __user *useraddr)
+static void amd8111e_get_drvinfo(struct net_device* dev, struct ethtool_drvinfo *info)
 {
        struct amd8111e_priv *lp = netdev_priv(dev);
        struct pci_dev *pci_dev = lp->pci_dev;
-       u32 ethcmd;
-       
-       if( useraddr == NULL) 
+       strcpy (info->driver, MODULE_NAME);
+       strcpy (info->version, MODULE_VERS);
+       sprintf(info->fw_version,"%u",chip_version);
+       strcpy (info->bus_info, pci_name(pci_dev));
+}
+
+static int amd8111e_get_regs_len(struct net_device *dev)
+{
+       return AMD8111E_REG_DUMP_LEN;
+}
+
+static void amd8111e_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
+{
+       struct amd8111e_priv *lp = netdev_priv(dev);
+       regs->version = 0;
+       amd8111e_read_regs(lp, buf);
+}
+
+static int amd8111e_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct amd8111e_priv *lp = netdev_priv(dev);
+       spin_lock_irq(&lp->lock);
+       mii_ethtool_gset(&lp->mii_if, ecmd);
+       spin_unlock_irq(&lp->lock);
+       return 0;
+}
+
+static int amd8111e_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct amd8111e_priv *lp = netdev_priv(dev);
+       int res;
+       spin_lock_irq(&lp->lock);
+       res = mii_ethtool_sset(&lp->mii_if, ecmd);
+       spin_unlock_irq(&lp->lock);
+       return res;
+}
+
+static int amd8111e_nway_reset(struct net_device *dev)
+{
+       struct amd8111e_priv *lp = netdev_priv(dev);
+       return mii_nway_restart(&lp->mii_if);
+}
+
+static u32 amd8111e_get_link(struct net_device *dev)
+{
+       struct amd8111e_priv *lp = netdev_priv(dev);
+       return mii_link_ok(&lp->mii_if);
+}
+
+static void amd8111e_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol_info)
+{
+       struct amd8111e_priv *lp = netdev_priv(dev);
+       wol_info->supported = WAKE_MAGIC|WAKE_PHY;
+       if (lp->options & OPTION_WOL_ENABLE)
+               wol_info->wolopts = WAKE_MAGIC;
+}
+
+static int amd8111e_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol_info)
+{
+       struct amd8111e_priv *lp = netdev_priv(dev);
+       if (wol_info->wolopts & ~(WAKE_MAGIC|WAKE_PHY))
                return -EINVAL;
-       if(copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
-               return -EFAULT;
-       
-       switch(ethcmd){
-       
-       case ETHTOOL_GDRVINFO:{
-               struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-               strcpy (info.driver, MODULE_NAME);
-               strcpy (info.version, MODULE_VERS);
-               memset(&info.fw_version, 0, sizeof(info.fw_version));
-               sprintf(info.fw_version,"%u",chip_version);
-               strcpy (info.bus_info, pci_name(pci_dev));
-               info.eedump_len = 0;
-               info.regdump_len = AMD8111E_REG_DUMP_LEN;
-               if (copy_to_user (useraddr, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       /* get settings */
-       case ETHTOOL_GSET: {
-               struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-               spin_lock_irq(&lp->lock);
-               mii_ethtool_gset(&lp->mii_if, &ecmd);
-               spin_unlock_irq(&lp->lock);
-               if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-                       return -EFAULT;
-               return 0;
-       }
-       /* set settings */
-       case ETHTOOL_SSET: {
-               int r;
-               struct ethtool_cmd ecmd;
-               if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-                       return -EFAULT;
+       spin_lock_irq(&lp->lock);
+       if (wol_info->wolopts & WAKE_MAGIC)
+               lp->options |= 
+                       (OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE);
+       else if(wol_info->wolopts & WAKE_PHY)
+               lp->options |= 
+                       (OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE);
+       else
+               lp->options &= ~OPTION_WOL_ENABLE; 
+       spin_unlock_irq(&lp->lock);
+       return 0;
+}
 
-               spin_lock_irq(&lp->lock);
-               r = mii_ethtool_sset(&lp->mii_if, &ecmd);
-               spin_unlock_irq(&lp->lock);
-               return r;
-       }
-       case ETHTOOL_GREGS: {
-               struct ethtool_regs regs;
-               u8 *regbuf;
-               int ret;
-
-               if (copy_from_user(&regs, useraddr, sizeof(regs)))
-                       return -EFAULT;
-               if (regs.len > AMD8111E_REG_DUMP_LEN)
-                       regs.len = AMD8111E_REG_DUMP_LEN;
-               regs.version = 0;
-               if (copy_to_user(useraddr, &regs, sizeof(regs)))
-                       return -EFAULT;
-
-               regbuf = amd8111e_read_regs(lp);
-               if (!regbuf)
-                       return -ENOMEM;
-
-               useraddr += offsetof(struct ethtool_regs, data);
-               ret = 0;
-               if (copy_to_user(useraddr, regbuf, regs.len))
-                       ret = -EFAULT;
-               kfree(regbuf);
-               return ret;
-       }
-       /* restart autonegotiation */
-       case ETHTOOL_NWAY_RST: {
-               return mii_nway_restart(&lp->mii_if);
-       }
-       /* get link status */
-       case ETHTOOL_GLINK: {
-               struct ethtool_value val = {ETHTOOL_GLINK};
-               val.data = mii_link_ok(&lp->mii_if);
-               if (copy_to_user(useraddr, &val, sizeof(val)))
-                       return -EFAULT;
-               return 0;
-       }
-       case ETHTOOL_GWOL: {
-               struct ethtool_wolinfo wol_info = { ETHTOOL_GWOL };
-
-               wol_info.supported = WAKE_MAGIC|WAKE_PHY;
-               wol_info.wolopts = 0;
-               if (lp->options & OPTION_WOL_ENABLE)
-                       wol_info.wolopts = WAKE_MAGIC;
-               memset(&wol_info.sopass, 0, sizeof(wol_info.sopass));
-               if (copy_to_user(useraddr, &wol_info, sizeof(wol_info)))
-                       return -EFAULT;
-               return 0;
-       }
-       case ETHTOOL_SWOL: {
-               struct ethtool_wolinfo wol_info;
+static struct ethtool_ops ops = {
+       .get_drvinfo = amd8111e_get_drvinfo,
+       .get_regs_len = amd8111e_get_regs_len,
+       .get_regs = amd8111e_get_regs,
+       .get_settings = amd8111e_get_settings,
+       .set_settings = amd8111e_set_settings,
+       .nway_reset = amd8111e_nway_reset,
+       .get_link = amd8111e_get_link,
+       .get_wol = amd8111e_get_wol,
+       .set_wol = amd8111e_set_wol,
+};
 
-               if (copy_from_user(&wol_info, useraddr, sizeof(wol_info)))
-                       return -EFAULT;
-               if (wol_info.wolopts & ~(WAKE_MAGIC |WAKE_PHY))
-                       return -EINVAL;
-               spin_lock_irq(&lp->lock);
-               if(wol_info.wolopts & WAKE_MAGIC)
-                       lp->options |= 
-                               (OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE);
-               else if(wol_info.wolopts & WAKE_PHY)
-                       lp->options |= 
-                               (OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE);
-               else
-                       lp->options &= ~OPTION_WOL_ENABLE; 
-               spin_unlock_irq(&lp->lock);
-               return 0;
-       }
+/*
+This function handles all the  ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application. 
+*/
        
-       default:
-               break;
-       }
-               return -EOPNOTSUPP;
-}
 static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
 {
        struct mii_ioctl_data *data = if_mii(ifr);
@@ -1703,10 +1666,8 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
                return -EPERM;
 
        switch(cmd) {
-       case SIOCETHTOOL:
-               return amd8111e_ethtool_ioctl(dev, ifr->ifr_data);
        case SIOCGMIIPHY:
-               data->phy_id = PHY_ID;
+               data->phy_id = lp->ext_phy_addr;
 
        /* fallthru */
        case SIOCGMIIREG: 
@@ -1736,7 +1697,7 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
 }
 static int amd8111e_set_mac_address(struct net_device *dev, void *p)
 {
-       struct amd8111e_priv *lp = dev->priv;
+       struct amd8111e_priv *lp = netdev_priv(dev);
        int i;
        struct sockaddr *addr = p;
 
@@ -1874,7 +1835,7 @@ static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state)
                pci_enable_wake(pci_dev, 4, 0); /* 4 == D3 cold */
        }
        
-       pci_save_state(pci_dev, lp->pm_state);
+       pci_save_state(pci_dev);
        pci_set_power_state(pci_dev, 3);
 
        return 0;
@@ -1888,7 +1849,7 @@ static int amd8111e_resume(struct pci_dev *pci_dev)
                return 0;
 
        pci_set_power_state(pci_dev, 0);
-       pci_restore_state(pci_dev, lp->pm_state);
+       pci_restore_state(pci_dev);
 
        pci_enable_wake(pci_dev, 3, 0);
        pci_enable_wake(pci_dev, 4, 0); /* D3 cold */
@@ -1912,7 +1873,7 @@ static void __devexit amd8111e_remove_one(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        if (dev) {
                unregister_netdev(dev);
-               iounmap((void *) ((struct amd8111e_priv *)(dev->priv))->mmio);
+               iounmap(((struct amd8111e_priv *)netdev_priv(dev))->mmio);
                free_netdev(dev);
                pci_release_regions(pdev);
                pci_disable_device(pdev);
@@ -1923,7 +1884,7 @@ static void amd8111e_config_ipg(struct net_device* dev)
 {
        struct amd8111e_priv *lp = netdev_priv(dev);
        struct ipg_info* ipg_data = &lp->ipg_data;
-       void mmio = lp->mmio;
+       void __iomem *mmio = lp->mmio;
        unsigned int prev_col_cnt = ipg_data->col_cnt;
        unsigned int total_col_cnt;
        unsigned int tmp_ipg;
@@ -1979,6 +1940,26 @@ static void amd8111e_config_ipg(struct net_device* dev)
 
 }
 
+static void __devinit amd8111e_probe_ext_phy(struct net_device* dev)
+{
+       struct amd8111e_priv *lp = netdev_priv(dev);
+       int i;
+
+       for (i = 0x1e; i >= 0; i--) {
+               u32 id1, id2;
+
+               if (amd8111e_read_phy(lp, i, MII_PHYSID1, &id1))
+                       continue;
+               if (amd8111e_read_phy(lp, i, MII_PHYSID2, &id2))
+                       continue;
+               lp->ext_phy_id = (id1 << 16) | id2;
+               lp->ext_phy_addr = i;
+               return;
+       }
+       lp->ext_phy_id = 0;
+       lp->ext_phy_addr = 1;
+}
+
 static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
                                  const struct pci_device_id *ent)
 {
@@ -2049,12 +2030,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
        lp->amd8111e_net_dev = dev;
        lp->pm_cap = pm_cap;
 
-       /* setting mii default values */
-       lp->mii_if.dev = dev;
-       lp->mii_if.mdio_read = amd8111e_mdio_read;
-       lp->mii_if.mdio_write = amd8111e_mdio_write;
-       lp->mii_if.phy_id = PHY_ID;
-
        spin_lock_init(&lp->lock);
 
        lp->mmio = ioremap(reg_addr, reg_len);
@@ -2085,6 +2060,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
        dev->set_mac_address = amd8111e_set_mac_address;
        dev->do_ioctl = amd8111e_ioctl;
        dev->change_mtu = amd8111e_change_mtu;
+       SET_ETHTOOL_OPS(dev, &ops);
        dev->irq =pdev->irq;
        dev->tx_timeout = amd8111e_tx_timeout; 
        dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; 
@@ -2101,7 +2077,15 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
        dev->vlan_rx_register =amd8111e_vlan_rx_register;
        dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;
 #endif 
-       
+       /* Probe the external PHY */
+       amd8111e_probe_ext_phy(dev);
+
+       /* setting mii default values */
+       lp->mii_if.dev = dev;
+       lp->mii_if.mdio_read = amd8111e_mdio_read;
+       lp->mii_if.mdio_write = amd8111e_mdio_write;
+       lp->mii_if.phy_id = lp->ext_phy_addr;
+
        /* Set receive buffer length and set jumbo option*/
        amd8111e_set_rx_buff_len(dev);
 
@@ -2134,9 +2118,15 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
        for (i = 0; i < 6; i++)
                printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':');
        printk( "\n");  
+       if (lp->ext_phy_id)
+               printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n",
+                      dev->name, lp->ext_phy_id, lp->ext_phy_addr);
+       else
+               printk(KERN_INFO "%s: Couldn't detect MII PHY, assuming address 0x01\n",
+                      dev->name);
        return 0;
 err_iounmap:
-       iounmap((void *) lp->mmio);
+       iounmap(lp->mmio);
 
 err_free_dev:
        free_netdev(dev);
index f95425d..cfe3a42 100755 (executable)
@@ -649,7 +649,6 @@ typedef enum {
 #define TCC_MASK               0x0003
 
 /* driver ioctl parameters */
-#define PHY_ID                         0x01    /* currently it is fixed */
 #define AMD8111E_REG_DUMP_LEN   13*sizeof(u32) 
 
 /* crc generator constants */
@@ -766,7 +765,7 @@ struct amd8111e_priv{
        dma_addr_t tx_dma_addr[NUM_TX_BUFFERS];
        dma_addr_t rx_dma_addr[NUM_RX_BUFFERS];
        /* Reg memory mapped address */
-       void *  mmio;
+       void __iomem *mmio;
        
        spinlock_t lock;        /* Guard lock */
        unsigned long rx_idx, tx_idx;   /* The next free ring entry */
@@ -777,10 +776,11 @@ struct amd8111e_priv{
        int options;            /* Options enabled/disabled for the device */
 
        unsigned long ext_phy_option;
+       int ext_phy_addr;
+       u32 ext_phy_id;
        
        struct amd8111e_link_config link_config;
        int pm_cap;
-       u32 pm_state[12];
 
        struct net_device *next;
        int mii;
index 925dd04..00bb1b2 100644 (file)
@@ -69,9 +69,9 @@ static const char *version =
 #include <linux/delay.h>       /* For udelay() */
 #include <linux/atalk.h>
 #include <linux/spinlock.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
index 10a94c5..9fe93ac 100644 (file)
@@ -47,8 +47,8 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/zorro.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
 #include <asm/irq.h>
index 6b28a3d..9b659e3 100644 (file)
@@ -28,9 +28,9 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -630,6 +630,16 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_RETVAL(handled);
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void am79c961_poll_controller(struct net_device *dev)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       am79c961_interrupt(dev->irq, dev, NULL);
+       local_irq_restore(flags);
+}
+#endif
+
 /*
  * Initialise the chip.  Note that we always expect
  * to be entered with interrupts enabled.
@@ -721,6 +731,9 @@ static int __init am79c961_init(void)
        dev->get_stats          = am79c961_getstats;
        dev->set_multicast_list = am79c961_setmulticastlist;
        dev->tx_timeout         = am79c961_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller    = am79c961_poll_controller;
+#endif
 
        ret = register_netdev(dev);
        if (ret == 0)
index fb401b2..6118f09 100644 (file)
@@ -48,9 +48,9 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/ecard.h>
index d054876..e0d22a3 100644 (file)
@@ -64,9 +64,9 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/ecard.h>
 #include <asm/io.h>
 #include <asm/irq.h>
index 92a2ec2..1798ce7 100644 (file)
@@ -97,6 +97,7 @@ static char version[] =
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -105,7 +106,6 @@ static char version[] =
 #include <asm/setup.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/atarihw.h>
index c74e586..81c362c 100644 (file)
@@ -88,9 +88,9 @@ static char *version =
 #include <linux/in.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/bitops.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/errno.h>
index e462e2f..ad01121 100644 (file)
@@ -56,12 +56,12 @@ static char version[] = "atarilance.c: v1.3 04/04/96 "
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 
 /* Debug level:
@@ -606,7 +606,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
                printk( "      Use \"ifconfig hw ether ...\" to set the address.\n" );
        }
 
-       lp->devlock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&lp->devlock);
 
        MEM->init.mode = 0x0000;                /* Disable Rx and Tx. */
        for( i = 0; i < 6; i++ )
index fd2e033..662e40f 100644 (file)
@@ -141,9 +141,9 @@ static int xcvr[NUM_UNITS];                         /* The data transfer mode. */
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
index afcdcff..3328ed5 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/crc32.h>
+#include <linux/bitops.h>
 
 #include <asm/mipsregs.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/au1000.h>
 
index e62ad3a..55a0f66 100644 (file)
@@ -25,9 +25,9 @@ static char *version = "bagetlance.c: v1.1 11/10/98\n";
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/baget/baget.h>
 
index c07cf2c..8c32530 100644 (file)
@@ -36,8 +36,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION    "2.6.0"
-#define DRV_RELDATE    "January 14, 2004"
+#define DRV_VERSION    "2.6.1"
+#define DRV_RELDATE    "October 29, 2004"
 #define DRV_NAME       "bonding"
 #define DRV_DESCRIPTION        "Ethernet Channel Bonding Driver"
 
index 409b754..3d88ad6 100644 (file)
@@ -1160,7 +1160,7 @@ static struct compressor ppp_bsd_compress = {
  * Module support routines
  *************************************************************/
 
-int __init bsdcomp_init(void)
+static int __init bsdcomp_init(void)
 {
        int answer = ppp_register_compressor(&ppp_bsd_compress);
        if (answer == 0)
@@ -1168,7 +1168,7 @@ int __init bsdcomp_init(void)
        return answer;
 }
 
-void __exit bsdcomp_cleanup(void)
+static void __exit bsdcomp_cleanup(void)
 {
        ppp_unregister_compressor(&ppp_bsd_compress);
 }
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);
index 7f62a43..521c831 100644 (file)
@@ -812,12 +812,6 @@ static int lance_open(struct net_device *dev)
        }
 
        status = init_restart_lance(lp);
-
-       /*
-        * if (!status)
-        *      MOD_INC_USE_COUNT;
-        */
-
        return status;
 }
 
@@ -849,9 +843,6 @@ static int lance_close(struct net_device *dev)
                free_irq(lp->dma_irq, dev);
        }
        free_irq(dev->irq, dev);
-       /*
-          MOD_DEC_USE_COUNT;
-        */
        return 0;
 }
 
index 6a04896..a480b80 100644 (file)
@@ -16,7 +16,7 @@
  *   LVS       Lawrence V. Stefani <lstefani@yahoo.com>
  *
  * Maintainers:
- *   macro     Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ *   macro     Maciej W. Rozycki <macro@linux-mips.org>
  *
  * Modification History:
  *             Date            Name    Description
index 5d62a03..28109cb 100644 (file)
 #include <linux/ctype.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
+#include <linux/bitops.h>
 
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
@@ -666,7 +666,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
                outb(nicsr, DEPCA_NICSR);
        }
 
-       lp->lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&lp->lock);
        sprintf(lp->adapter_name, "%s (%s)",
                depca_signature[lp->adapter], device->bus_id);
        status = -EBUSY;
@@ -1222,10 +1222,10 @@ static int InitRestartDepca(struct net_device *dev)
                /* clear IDON by writing a "1", enable interrupts and start lance */
                outw(IDON | INEA | STRT, DEPCA_DATA);
                if (depca_debug > 2) {
-                       printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
+                       printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
                }
        } else {
-               printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
+               printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
                status = -1;
        }
 
@@ -1901,7 +1901,7 @@ static void depca_dbg_open(struct net_device *dev)
                        }
                }
                printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
-               printk("Initialisation block at 0x%8.8lx(Phys)\n", virt_to_phys(lp->sh_mem));
+               printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start);
                printk("        mode: 0x%4.4x\n", p->mode);
                printk("        physical address: ");
                for (i = 0; i < ETH_ALEN - 1; i++) {
@@ -1915,7 +1915,7 @@ static void depca_dbg_open(struct net_device *dev)
                printk("%2.2x\n", p->mcast_table[i]);
                printk("        rx_ring at: 0x%8.8x\n", p->rx_ring);
                printk("        tx_ring at: 0x%8.8x\n", p->tx_ring);
-               printk("buffers (Phys): 0x%8.8lx\n", virt_to_phys(lp->sh_mem) + lp->buffs_offset);
+               printk("buffers (Phys): 0x%8.8lx\n", lp->mem_start + lp->buffs_offset);
                printk("Ring size:\nRX: %d  Log2(rxRingMask): 0x%8.8x\n", (int) lp->rxRingMask + 1, lp->rx_rlen);
                printk("TX: %d  Log2(txRingMask): 0x%8.8x\n", (int) lp->txRingMask + 1, lp->tx_rlen);
                outw(CSR2, DEPCA_ADDR);
index 53f01d5..575896c 100644 (file)
@@ -107,7 +107,6 @@ static int change_mtu (struct net_device *dev, int new_mtu);
 static void set_multicast (struct net_device *dev);
 static struct net_device_stats *get_stats (struct net_device *dev);
 static int clear_stats (struct net_device *dev);
-static int rio_ethtool_ioctl (struct net_device *dev, void __user *useraddr);
 static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static int rio_close (struct net_device *dev);
 static int find_miiphy (struct net_device *dev);
@@ -122,6 +121,8 @@ static int mii_read (struct net_device *dev, int phy_addr, int reg_num);
 static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
                      u16 data);
 
+static struct ethtool_ops ethtool_ops;
+
 static int __devinit
 rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -168,7 +169,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
 #endif
        dev->base_addr = ioaddr;
        dev->irq = irq;
-       np = dev->priv;
+       np = netdev_priv(dev);
        np->chip_id = chip_idx;
        np->pdev = pdev;
        spin_lock_init (&np->tx_lock);
@@ -244,6 +245,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
        dev->tx_timeout = &rio_tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
        dev->change_mtu = &change_mtu;
+       SET_ETHTOOL_OPS(dev, &ethtool_ops);
 #if 0
        dev->features = NETIF_F_IP_CSUM;
 #endif
@@ -335,7 +337,7 @@ find_miiphy (struct net_device *dev)
        int i, phy_found = 0;
        struct netdev_private *np;
        long ioaddr;
-       np = dev->priv;
+       np = netdev_priv(dev);
        ioaddr = dev->base_addr;
        np->phy_addr = 1;
 
@@ -362,7 +364,7 @@ parse_eeprom (struct net_device *dev)
        u8 *psib;
        u32 crc;
        PSROM_t psrom = (PSROM_t) sromdata;
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
 
        int cid, next;
 
@@ -432,7 +434,7 @@ parse_eeprom (struct net_device *dev)
 static int
 rio_open (struct net_device *dev)
 {
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        long ioaddr = dev->base_addr;
        int i;
        u16 macctrl;
@@ -516,7 +518,7 @@ static void
 rio_timer (unsigned long data)
 {
        struct net_device *dev = (struct net_device *)data;
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        unsigned int entry;
        int next_tick = 1*HZ;
        unsigned long flags;
@@ -574,7 +576,7 @@ rio_tx_timeout (struct net_device *dev)
 static void
 alloc_list (struct net_device *dev)
 {
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        int i;
 
        np->cur_rx = np->cur_tx = 0;
@@ -631,7 +633,7 @@ alloc_list (struct net_device *dev)
 static int
 start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        struct netdev_desc *txdesc;
        unsigned entry;
        u32 ioaddr;
@@ -711,7 +713,7 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
        int handled = 0;
 
        ioaddr = dev->base_addr;
-       np = dev->priv;
+       np = netdev_priv(dev);
        while (1) {
                int_status = readw (ioaddr + IntStatus); 
                writew (int_status, ioaddr + IntStatus);
@@ -745,7 +747,7 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
 static void 
 rio_free_tx (struct net_device *dev, int irq) 
 {
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        int entry = np->old_tx % TX_RING_SIZE;
        int tx_use = 0;
        unsigned long flag = 0;
@@ -798,7 +800,7 @@ tx_error (struct net_device *dev, int tx_status)
        int frame_id;
        int i;
 
-       np = dev->priv;
+       np = netdev_priv(dev);
 
        frame_id = (tx_status & 0xffff0000);
        printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n",
@@ -855,7 +857,7 @@ tx_error (struct net_device *dev, int tx_status)
 static int
 receive_packet (struct net_device *dev)
 {
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        int entry = np->cur_rx % RX_RING_SIZE;
        int cnt = 30;
 
@@ -965,7 +967,7 @@ static void
 rio_error (struct net_device *dev, int int_status)
 {
        long ioaddr = dev->base_addr;
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        u16 macctrl;
 
        /* Link change event */
@@ -1016,7 +1018,7 @@ static struct net_device_stats *
 get_stats (struct net_device *dev)
 {
        long ioaddr = dev->base_addr;
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
 #ifdef MEM_MAPPING
        int i;
 #endif
@@ -1132,7 +1134,7 @@ clear_stats (struct net_device *dev)
 int
 change_mtu (struct net_device *dev, int new_mtu)
 {
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        int max = (np->jumbo) ? MAX_JUMBO : 1536;
 
        if ((new_mtu < 68) || (new_mtu > max)) {
@@ -1150,7 +1152,7 @@ set_multicast (struct net_device *dev)
        long ioaddr = dev->base_addr;
        u32 hash_table[2];
        u16 rx_mode = 0;
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        
        hash_table[0] = hash_table[1] = 0;
        /* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
@@ -1194,137 +1196,118 @@ set_multicast (struct net_device *dev)
        writew (rx_mode, ioaddr + ReceiveMode);
 }
 
-static int
-rio_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
+static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       strcpy(info->driver, "DL2K");
+       strcpy(info->version, DRV_VERSION);
+       strcpy(info->bus_info, pci_name(np->pdev));
+}      
+
+static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct netdev_private *np = dev->priv;
-               u32 ethcmd;
+       struct netdev_private *np = netdev_priv(dev);
+       if (np->phy_media) {
+               /* fiber device */
+               cmd->supported = SUPPORTED_Autoneg | SUPPORTED_FIBRE;
+               cmd->advertising= ADVERTISED_Autoneg | ADVERTISED_FIBRE;
+               cmd->port = PORT_FIBRE;
+               cmd->transceiver = XCVR_INTERNAL;       
+       } else {
+               /* copper device */
+               cmd->supported = SUPPORTED_10baseT_Half | 
+                       SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
+                       | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
+                       SUPPORTED_Autoneg | SUPPORTED_MII;
+               cmd->advertising = ADVERTISED_10baseT_Half |
+                       ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
+                       ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full|
+                       ADVERTISED_Autoneg | ADVERTISED_MII;
+               cmd->port = PORT_MII;
+               cmd->transceiver = XCVR_INTERNAL;
+       }
+       if ( np->link_status ) { 
+               cmd->speed = np->speed;
+               cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+       } else {
+               cmd->speed = -1;
+               cmd->duplex = -1;
+       }
+       if ( np->an_enable)
+               cmd->autoneg = AUTONEG_ENABLE;
+       else
+               cmd->autoneg = AUTONEG_DISABLE;
        
-       if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
-               return -EFAULT;
-       switch (ethcmd) {
-               case ETHTOOL_GDRVINFO: {
-                       struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-                       strcpy(info.driver, "DL2K");
-                       strcpy(info.version, DRV_VERSION);
-                       strcpy(info.bus_info, pci_name(np->pdev));
-                       memset(&info.fw_version, 0, sizeof(info.fw_version));
-                       if (copy_to_user(useraddr, &info, sizeof(info)))
-                               return -EFAULT;
+       cmd->phy_address = np->phy_addr;
+       return 0;                                  
+}
+
+static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       netif_carrier_off(dev);
+       if (cmd->autoneg == AUTONEG_ENABLE) {
+               if (np->an_enable)
                        return 0;
+               else {
+                       np->an_enable = 1;
+                       mii_set_media(dev);
+                       return 0;       
                }       
-       
-               case ETHTOOL_GSET: {
-                       struct ethtool_cmd cmd = { ETHTOOL_GSET };
-                       if (np->phy_media) {
-                               /* fiber device */
-                               cmd.supported = SUPPORTED_Autoneg | 
-                                                       SUPPORTED_FIBRE;
-                               cmd.advertising= ADVERTISED_Autoneg |
-                                                       ADVERTISED_FIBRE;
-                               cmd.port = PORT_FIBRE;
-                               cmd.transceiver = XCVR_INTERNAL;        
-                       } else {
-                               /* copper device */
-                               cmd.supported = SUPPORTED_10baseT_Half | 
-                                       SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
-                                       | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
-                                       SUPPORTED_Autoneg | SUPPORTED_MII;
-                               cmd.advertising = ADVERTISED_10baseT_Half |
-                                       ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
-                                       ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full|
-                                       ADVERTISED_Autoneg | ADVERTISED_MII;
-                               cmd.port = PORT_MII;
-                               cmd.transceiver = XCVR_INTERNAL;
-                       }
-                       if ( np->link_status ) { 
-                               cmd.speed = np->speed;
-                               cmd.duplex = np->full_duplex ? 
-                                                   DUPLEX_FULL : DUPLEX_HALF;
-                       } else {
-                               cmd.speed = -1;
-                               cmd.duplex = -1;
-                       }
-                       if ( np->an_enable)
-                               cmd.autoneg = AUTONEG_ENABLE;
-                       else
-                               cmd.autoneg = AUTONEG_DISABLE;
-                       
-                       cmd.phy_address = np->phy_addr;
-
-                       if (copy_to_user(useraddr, &cmd,
-                                       sizeof(cmd)))
-                               return -EFAULT;
-                       return 0;                                  
-               }
-               case ETHTOOL_SSET: {
-                       struct ethtool_cmd cmd;
-                       if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
-                               return -EFAULT;
-                       netif_carrier_off(dev);
-                       if (cmd.autoneg == AUTONEG_ENABLE) {
-                               if (np->an_enable)
-                                       return 0;
-                               else {
-                                       np->an_enable = 1;
-                                       mii_set_media(dev);
-                                       return 0;       
-                               }       
-                       } else {
-                               np->an_enable = 0;
-                               if (np->speed == 1000){
-                                       cmd.speed = SPEED_100;                  
-                                       cmd.duplex = DUPLEX_FULL;
-                                       printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manul 100Mbps, Full duplex.\n");
-                                       }
-                               switch(cmd.speed + cmd.duplex){
-                               
-                               case SPEED_10 + DUPLEX_HALF:
-                                       np->speed = 10;
-                                       np->full_duplex = 0;
-                                       break;
-                               
-                               case SPEED_10 + DUPLEX_FULL:
-                                       np->speed = 10;
-                                       np->full_duplex = 1;
-                                       break;
-                               case SPEED_100 + DUPLEX_HALF:
-                                       np->speed = 100;
-                                       np->full_duplex = 0;
-                                       break;
-                               case SPEED_100 + DUPLEX_FULL:
-                                       np->speed = 100;
-                                       np->full_duplex = 1;
-                                       break;
-                               case SPEED_1000 + DUPLEX_HALF:/* not supported */
-                               case SPEED_1000 + DUPLEX_FULL:/* not supported */
-                               default:
-                                       return -EINVAL; 
-                               }
-                               mii_set_media(dev);
-                       }
-               return 0;                  
+       } else {
+               np->an_enable = 0;
+               if (np->speed == 1000) {
+                       cmd->speed = SPEED_100;                 
+                       cmd->duplex = DUPLEX_FULL;
+                       printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n");
                }
-#ifdef ETHTOOL_GLINK           
-               case ETHTOOL_GLINK:{
-               struct ethtool_value link = { ETHTOOL_GLINK };
-               link.data = np->link_status;
-               if (copy_to_user(useraddr, &link, sizeof(link)))
-                       return -EFAULT;
-               return 0;
-               }                          
-#endif
+               switch(cmd->speed + cmd->duplex) {
+               
+               case SPEED_10 + DUPLEX_HALF:
+                       np->speed = 10;
+                       np->full_duplex = 0;
+                       break;
+               
+               case SPEED_10 + DUPLEX_FULL:
+                       np->speed = 10;
+                       np->full_duplex = 1;
+                       break;
+               case SPEED_100 + DUPLEX_HALF:
+                       np->speed = 100;
+                       np->full_duplex = 0;
+                       break;
+               case SPEED_100 + DUPLEX_FULL:
+                       np->speed = 100;
+                       np->full_duplex = 1;
+                       break;
+               case SPEED_1000 + DUPLEX_HALF:/* not supported */
+               case SPEED_1000 + DUPLEX_FULL:/* not supported */
                default:
-               return -EOPNOTSUPP;
-       }       
+                       return -EINVAL; 
+               }
+               mii_set_media(dev);
+       }
+       return 0;
+}
+
+static u32 rio_get_link(struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       return np->link_status;
 }
 
+static struct ethtool_ops ethtool_ops = {
+       .get_drvinfo = rio_get_drvinfo,
+       .get_settings = rio_get_settings,
+       .set_settings = rio_set_settings,
+       .get_link = rio_get_link,
+};
 
 static int
 rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
        int phy_addr;
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        struct mii_data *miidata = (struct mii_data *) &rq->ifr_ifru;
        
        struct netdev_desc *desc;
@@ -1332,8 +1315,6 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 
        phy_addr = np->phy_addr;
        switch (cmd) {
-       case SIOCETHTOOL:
-               return rio_ethtool_ioctl(dev, rq->ifr_data);            
        case SIOCDEVPRIVATE:
                break;
        
@@ -1490,7 +1471,7 @@ mii_wait_link (struct net_device *dev, int wait)
        int phy_addr;
        struct netdev_private *np;
 
-       np = dev->priv;
+       np = netdev_priv(dev);
        phy_addr = np->phy_addr;
 
        do {
@@ -1512,7 +1493,7 @@ mii_get_media (struct net_device *dev)
        int phy_addr;
        struct netdev_private *np;
 
-       np = dev->priv;
+       np = netdev_priv(dev);
        phy_addr = np->phy_addr;
 
        bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
@@ -1594,7 +1575,7 @@ mii_set_media (struct net_device *dev)
        ANAR_t anar;
        int phy_addr;
        struct netdev_private *np;
-       np = dev->priv;
+       np = netdev_priv(dev);
        phy_addr = np->phy_addr;
 
        /* Does user set speed? */
@@ -1684,7 +1665,7 @@ mii_get_media_pcs (struct net_device *dev)
        int phy_addr;
        struct netdev_private *np;
 
-       np = dev->priv;
+       np = netdev_priv(dev);
        phy_addr = np->phy_addr;
 
        bmsr.image = mii_read (dev, phy_addr, PCS_BMSR);
@@ -1740,7 +1721,7 @@ mii_set_media_pcs (struct net_device *dev)
        ANAR_PCS_t anar;
        int phy_addr;
        struct netdev_private *np;
-       np = dev->priv;
+       np = netdev_priv(dev);
        phy_addr = np->phy_addr;
 
        /* Auto-Negotiation? */
@@ -1794,7 +1775,7 @@ static int
 rio_close (struct net_device *dev)
 {
        long ioaddr = dev->base_addr;
-       struct netdev_private *np = dev->priv;
+       struct netdev_private *np = netdev_priv(dev);
        struct sk_buff *skb;
        int i;
 
@@ -1840,7 +1821,7 @@ rio_remove1 (struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata (pdev);
 
        if (dev) {
-               struct netdev_private *np = dev->priv;
+               struct netdev_private *np = netdev_priv(dev);
 
                unregister_netdev (dev);
                pci_free_consistent (pdev, RX_TOTAL_SIZE, np->rx_ring,
index d463673..6e75482 100644 (file)
@@ -28,8 +28,8 @@
 #include <linux/init.h>
 #include <linux/crc32.h>
 #include <linux/ethtool.h>
+#include <linux/bitops.h>
 #include <asm/processor.h>     /* Processor type for cache alignment. */
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/delay.h>
index 9e20868..630beaf 100644 (file)
                                set_current_state(TASK_UNINTERRUPTIBLE); \
                                schedule_timeout((x * HZ)/1000 + 2); \
                        } } while(0)
+/* Some workarounds require millisecond delays and are run during interrupt
+ * context.  Most notably, when establishing link, the phy may need tweaking
+ * but cannot process phy register reads/writes faster than millisecond
+ * intervals...and we establish link due to a "link status change" interrupt.
+ */
+#define msec_delay_irq(x) mdelay(x)
 #endif
 
 #define PCI_COMMAND_REGISTER   PCI_COMMAND
index ef47c5c..24f237b 100644 (file)
@@ -124,7 +124,7 @@ static int ethertap_open(struct net_device *dev)
        struct net_local *lp = netdev_priv(dev);
 
        if (ethertap_debug > 2)
-               printk(KERN_DEBUG "%s: Doing ethertap_open()...", dev->name);
+               printk(KERN_DEBUG "%s: Doing ethertap_open()...\n", dev->name);
 
        lp->nl = netlink_kernel_create(dev->base_addr, ethertap_rx);
        if (lp->nl == NULL)
index b9e59da..2c70084 100644 (file)
@@ -18,8 +18,8 @@
  * Much better multiple PHY support by Magnus Damm.
  * Copyright (c) 2000 Ericsson Radio Systems AB.
  *
- * Support for FEC controller of ColdFire/5272.
- * Copyrught (c) 2001-2002 Greg Ungerer (gerg@snapgear.com)
+ * Support for FEC controller of ColdFire/5270/5271/5272/5274/5275/5280/5282.
+ * Copyrught (c) 2001-2004 Greg Ungerer (gerg@snapgear.com)
  */
 
 #include <linux/config.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
+#include <linux/bitops.h>
 
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 
-#ifdef CONFIG_M5272
+#if defined(CONFIG_M527x) || defined(CONFIG_M5272) || defined(CONFIG_M528x)
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include "fec.h"
 #include "commproc.h"
 #endif
 
-static int opened = 0;
-static int found = 0;
+#if defined(CONFIG_FEC2)
+#define        FEC_MAX_PORTS   2
+#else
+#define        FEC_MAX_PORTS   1
+#endif
 
 /*
  * Define the fixed address of the FEC hardware.
  */
-#ifdef CONFIG_M5272
-static volatile fec_t   *fec_hwp = (volatile fec_t *) (MCF_MBAR + 0x840);
-static ushort          my_enet_addr[] = { 0x00d0, 0xcf00, 0x0072 };
+static unsigned int fec_hw[] = {
+#if defined(CONFIG_M5272)
+       (MCF_MBAR + 0x840),
+#elif defined(CONFIG_M527x)
+       (MCF_MBAR + 0x1000),
+       (MCF_MBAR + 0x1800),
+#elif defined(CONFIG_M528x)
+       (MCF_MBAR + 0x1000),
 #else
-static volatile fec_t  *fec_hwp = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec)
-static ushort          my_enet_addr[3];
-#endif /* CONFIG_M5272 */
+       &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec),
+#endif
+};
+
+static unsigned char   fec_mac_default[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
 
 /*
  * Some hardware gets it MAC address out of local flash memory.
@@ -76,10 +88,12 @@ static ushort               my_enet_addr[3];
  */
 #if defined(CONFIG_NETtel)
 #define        FEC_FLASHMAC    0xf0006006
-#elif defined(CONFIG_GILBARCONAP)
+#elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES)
 #define        FEC_FLASHMAC    0xf0006000
 #elif defined (CONFIG_MTD_KeyTechnology)
 #define        FEC_FLASHMAC    0xffe04000
+#elif defined(CONFIG_CANCam)
+#define        FEC_FLASHMAC    0xf0020000
 #else
 #define        FEC_FLASHMAC    0
 #endif
@@ -110,21 +124,14 @@ typedef struct {
  * We don't need to allocate pages for the transmitter.  We just use
  * the skbuffer directly.
  */
-#if 1
-#define FEC_ENET_RX_PAGES      4
-#define FEC_ENET_RX_FRSIZE     2048
-#define FEC_ENET_RX_FRPPG      (PAGE_SIZE / FEC_ENET_RX_FRSIZE)
-#define RX_RING_SIZE           (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
-#define TX_RING_SIZE           8       /* Must be power of two */
-#define TX_RING_MOD_MASK       7       /*   for this to work */
-#else
-#define FEC_ENET_RX_PAGES      16
+#define FEC_ENET_RX_PAGES      8
 #define FEC_ENET_RX_FRSIZE     2048
 #define FEC_ENET_RX_FRPPG      (PAGE_SIZE / FEC_ENET_RX_FRSIZE)
 #define RX_RING_SIZE           (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
+#define FEC_ENET_TX_FRSIZE     2048
+#define FEC_ENET_TX_FRPPG      (PAGE_SIZE / FEC_ENET_TX_FRSIZE)
 #define TX_RING_SIZE           16      /* Must be power of two */
 #define TX_RING_MOD_MASK       15      /*   for this to work */
-#endif
 
 /* Interrupt events/masks.
 */
@@ -145,6 +152,18 @@ typedef struct {
 #define PKT_MINBUF_SIZE                64
 #define PKT_MAXBLR_SIZE                1520
 
+
+/*
+ * The 5270/5271/5280/5282 RX control register also contains maximum frame
+ * size bits. Other FEC hardware does not, so we need to take that into
+ * account when setting it.
+ */
+#if defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#define        OPT_FRAME_SIZE  (PKT_MAXBUF_SIZE << 16)
+#else
+#define        OPT_FRAME_SIZE  0
+#endif
+
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
  * tx_bd_base always point to the base of the buffer descriptors.  The
  * cur_rx and cur_tx point to the currently available buffer.
@@ -154,7 +173,11 @@ typedef struct {
  * the buffer descriptor determines the actual condition.
  */
 struct fec_enet_private {
+       /* Hardware registers of the FEC device */
+       volatile fec_t  *hwp;
+
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+       unsigned char *tx_bounce[TX_RING_SIZE];
        struct  sk_buff* tx_skbuff[TX_RING_SIZE];
        ushort  skb_cur;
        ushort  skb_dirty;
@@ -177,12 +200,16 @@ struct fec_enet_private {
        struct work_struct phy_task;
 
        uint    sequence_done;
+       uint    mii_phy_task_queued;
 
        uint    phy_addr;
 
+       int     index;
+       int     opened;
        int     link;
        int     old_link;
        int     full_duplex;
+       unsigned char mac_addr[ETH_ALEN];
 };
 
 static int fec_enet_open(struct net_device *dev);
@@ -299,6 +326,18 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        bdp->cbd_bufaddr = __pa(skb->data);
        bdp->cbd_datlen = skb->len;
 
+       /*
+        *      On some FEC implementations data must be aligned on
+        *      4-byte boundaries. Use bounce buffers to copy data
+        *      and get it aligned. Ugh.
+        */
+       if (bdp->cbd_bufaddr & 0x3) {
+               unsigned int index;
+               index = bdp - fep->tx_bd_base;
+               memcpy(fep->tx_bounce[index], (void *) bdp->cbd_bufaddr, bdp->cbd_datlen);
+               bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]);
+       }
+
        /* Save skb pointer.
        */
        fep->tx_skbuff[fep->skb_cur] = skb;
@@ -407,10 +446,6 @@ fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
        */
        while ((int_events = fecp->fec_ievent) != 0) {
                fecp->fec_ievent = int_events;
-               if ((int_events & (FEC_ENET_HBERR | FEC_ENET_BABR |
-                                  FEC_ENET_BABT | FEC_ENET_EBERR)) != 0) {
-                       printk("FEC ERROR %x\n", int_events);
-               }
 
                /* Handle receive event in its own function.
                 */
@@ -542,7 +577,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
                printk("FEC ENET: rcv is not +last\n");
 #endif
 
-       if (!opened)
+       if (!fep->opened)
                goto rx_processing_done;
 
        /* Check for errors. */
@@ -646,7 +681,7 @@ fec_enet_mii(struct net_device *dev)
        uint            mii_reg;
 
        fep = netdev_priv(dev);
-       ep = fec_hwp;
+       ep = fep->hwp;
        mii_reg = ep->fec_mii_data;
        
        if ((mip = mii_head) == NULL) {
@@ -694,7 +729,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
                }
                else {
                        mii_head = mii_tail = mip;
-                       fec_hwp->fec_mii_data = regval;
+                       fep->hwp->fec_mii_data = regval;
                }
        }
        else {
@@ -1028,6 +1063,43 @@ static phy_info_t phy_info_am79c874 = {
        },
 };
 
+/* ------------------------------------------------------------------------- */
+/* Kendin KS8721BL phy                                                       */
+
+/* register definitions for the 8721 */
+
+#define MII_KS8721BL_RXERCR    21
+#define MII_KS8721BL_ICSR      22
+#define        MII_KS8721BL_PHYCR      31
+
+static phy_info_t phy_info_ks8721bl = {
+       0x00022161, 
+       "KS8721BL",
+       
+       (const phy_cmd_t []) {  /* config */  
+               { mk_mii_read(MII_REG_CR), mii_parse_cr },
+               { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+               { mk_mii_end, }
+       },
+       (const phy_cmd_t []) {  /* startup */
+               { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL },
+               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+               { mk_mii_read(MII_REG_SR), mii_parse_sr }, 
+               { mk_mii_end, }
+       },
+       (const phy_cmd_t []) { /* ack_int */
+               /* find out the current status */
+               { mk_mii_read(MII_REG_SR), mii_parse_sr },
+               /* we only need to read ISR to acknowledge */
+               { mk_mii_read(MII_KS8721BL_ICSR), NULL },
+               { mk_mii_end, }
+       },
+       (const phy_cmd_t []) {  /* shutdown */
+               { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL },
+               { mk_mii_end, }
+       },
+};
+
 /* ------------------------------------------------------------------------- */
 
 static phy_info_t *phy_info[] = {
@@ -1035,24 +1107,26 @@ static phy_info_t *phy_info[] = {
        &phy_info_lxt971,
        &phy_info_qs6612,
        &phy_info_am79c874,
+       &phy_info_ks8721bl,
        NULL
 };
 
 /* ------------------------------------------------------------------------- */
 
-static void
 #ifdef CONFIG_RPXCLASSIC
+static void
 mii_link_interrupt(void *dev_id);
 #else
+static irqreturn_t
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs);
 #endif
 
-#ifdef CONFIG_M5272
+#if defined(CONFIG_M5272)
 
 /*
  *     Code specific to Coldfire 5272 setup.
  */
-static void __inline__ fec_request_intrs(struct net_device *dev, volatile fec_t *fecp)
+static void __inline__ fec_request_intrs(struct net_device *dev)
 {
        volatile unsigned long *icrp;
 
@@ -1076,26 +1150,29 @@ static void __inline__ fec_request_intrs(struct net_device *dev, volatile fec_t
 static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
 {
        volatile fec_t *fecp;
-       fecp = fec_hwp;
 
-       fecp->fec_r_cntrl = 0x04;
+       fecp = fep->hwp;
+       fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
        fecp->fec_x_cntrl = 0x00;
 
-       /* Set MII speed to 2.5 MHz
-       */
-       fecp->fec_mii_speed = fep->phy_speed = 0x0e;
+       /*
+        * Set MII speed to 2.5 MHz
+        * See 5272 manual section 11.5.8: MSCR
+        */
+       fep->phy_speed = ((((MCF_CLK / 4) / (2500000 / 10)) + 5) / 10) * 2;
+       fecp->fec_mii_speed = fep->phy_speed;
 
        fec_restart(dev, 0);
 }
 
-static void __inline__ fec_get_mac(struct net_device *dev, struct fec_enet_private *fep)
+static void __inline__ fec_get_mac(struct net_device *dev)
 {
+       struct fec_enet_private *fep = netdev_priv(dev);
        volatile fec_t *fecp;
-       unsigned char *eap, *iap, tmpaddr[6];
+       unsigned char *iap, tmpaddr[6];
        int i;
 
-       fecp = fec_hwp;
-       eap = (unsigned char *) my_enet_addr;
+       fecp = fep->hwp;
 
        if (fec_flashmac) {
                /*
@@ -1105,18 +1182,24 @@ static void __inline__ fec_get_mac(struct net_device *dev, struct fec_enet_priva
                iap = fec_flashmac;
                if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
                    (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
-                       iap = eap;
+                       iap = fec_mac_default;
                if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
                    (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
-                       iap = eap;
+                       iap = fec_mac_default;
        } else {
                *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
                *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
                iap = &tmpaddr[0];
        }
 
-       for (i=0; i<6; i++)
-               dev->dev_addr[i] = *eap++ = *iap++;
+       for (i=0; i<ETH_ALEN; i++)
+               dev->dev_addr[i] = fep->mac_addr[i] = *iap++;
+
+       /* Adjust MAC if using default MAC address */
+       if (iap == fec_mac_default) {
+               dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] =
+                       iap[ETH_ALEN-1] + fep->index;
+       }
 }
 
 static void __inline__ fec_enable_phy_intr(void)
@@ -1151,12 +1234,167 @@ static void __inline__ fec_uncache(unsigned long addr)
 
 /* ------------------------------------------------------------------------- */
 
+#elif defined(CONFIG_M527x) || defined(CONFIG_M528x)
+
+/*
+ *     Code specific to Coldfire 5270/5271/5274/5275 and 5280/5282 setups.
+ */
+static void __inline__ fec_request_intrs(struct net_device *dev)
+{
+       struct fec_enet_private *fep;
+       int b;
+
+       fep = netdev_priv(dev);
+       b = (fep->index) ? 128 : 64;
+
+       /* Setup interrupt handlers. */
+       if (request_irq(b+23, fec_enet_interrupt, 0, "fec(TXF)", dev) != 0)
+               printk("FEC: Could not allocate FEC(TXF) IRQ(%d+23)!\n", b);
+       if (request_irq(b+24, fec_enet_interrupt, 0, "fec(TXB)", dev) != 0)
+               printk("FEC: Could not allocate FEC(TXB) IRQ(%d+24)!\n", b);
+       if (request_irq(b+25, fec_enet_interrupt, 0, "fec(TXFIFO)", dev) != 0)
+               printk("FEC: Could not allocate FEC(TXFIFO) IRQ(%d+25)!\n", b);
+       if (request_irq(b+26, fec_enet_interrupt, 0, "fec(TXCR)", dev) != 0)
+               printk("FEC: Could not allocate FEC(TXCR) IRQ(%d+26)!\n", b);
+
+       if (request_irq(b+27, fec_enet_interrupt, 0, "fec(RXF)", dev) != 0)
+               printk("FEC: Could not allocate FEC(RXF) IRQ(%d+27)!\n", b);
+       if (request_irq(b+28, fec_enet_interrupt, 0, "fec(RXB)", dev) != 0)
+               printk("FEC: Could not allocate FEC(RXB) IRQ(%d+28)!\n", b);
+
+       if (request_irq(b+29, fec_enet_interrupt, 0, "fec(MII)", dev) != 0)
+               printk("FEC: Could not allocate FEC(MII) IRQ(%d+29)!\n", b);
+       if (request_irq(b+30, fec_enet_interrupt, 0, "fec(LC)", dev) != 0)
+               printk("FEC: Could not allocate FEC(LC) IRQ(%d+30)!\n", b);
+       if (request_irq(b+31, fec_enet_interrupt, 0, "fec(HBERR)", dev) != 0)
+               printk("FEC: Could not allocate FEC(HBERR) IRQ(%d+31)!\n", b);
+       if (request_irq(b+32, fec_enet_interrupt, 0, "fec(GRA)", dev) != 0)
+               printk("FEC: Could not allocate FEC(GRA) IRQ(%d+32)!\n", b);
+       if (request_irq(b+33, fec_enet_interrupt, 0, "fec(EBERR)", dev) != 0)
+               printk("FEC: Could not allocate FEC(EBERR) IRQ(%d+33)!\n", b);
+       if (request_irq(b+34, fec_enet_interrupt, 0, "fec(BABT)", dev) != 0)
+               printk("FEC: Could not allocate FEC(BABT) IRQ(%d+34)!\n", b);
+       if (request_irq(b+35, fec_enet_interrupt, 0, "fec(BABR)", dev) != 0)
+               printk("FEC: Could not allocate FEC(BABR) IRQ(%d+35)!\n", b);
+
+       /* Unmask interrupts at ColdFire 5280/5282 interrupt controller */
+       {
+               volatile unsigned char  *icrp;
+               volatile unsigned long  *imrp;
+               int i;
+
+               b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0;
+               icrp = (volatile unsigned char *) (MCF_IPSBAR + b +
+                       MCFINTC_ICR0);
+               for (i = 23; (i < 36); i++)
+                       icrp[i] = 0x23;
+
+               imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
+                       MCFINTC_IMRH);
+               *imrp &= ~0x0000000f;
+               imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
+                       MCFINTC_IMRL);
+               *imrp &= ~0xff800001;
+       }
+
+#if defined(CONFIG_M528x)
+       /* Set up gpio outputs for MII lines */
+       {
+               volatile unsigned short *gpio_paspar;
+  
+               gpio_paspar = (volatile unsigned short *) (MCF_IPSBAR +
+                       0x100056);
+               *gpio_paspar = 0x0f00;
+       }
+#endif
+}
+
+static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
+{
+       volatile fec_t *fecp;
+
+       fecp = fep->hwp;
+       fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
+       fecp->fec_x_cntrl = 0x00;
+
+       /*
+        * Set MII speed to 2.5 MHz
+        * See 5282 manual section 17.5.4.7: MSCR
+        */
+       fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
+       fecp->fec_mii_speed = fep->phy_speed;
+
+       fec_restart(dev, 0);
+}
+
+static void __inline__ fec_get_mac(struct net_device *dev)
+{
+       struct fec_enet_private *fep = netdev_priv(dev);
+       volatile fec_t *fecp;
+       unsigned char *iap, tmpaddr[6];
+       int i;
+
+       fecp = fep->hwp;
+
+       if (fec_flashmac) {
+               /*
+                * Get MAC address from FLASH.
+                * If it is all 1's or 0's, use the default.
+                */
+               iap = fec_flashmac;
+               if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
+                   (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
+                       iap = fec_mac_default;
+               if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
+                   (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
+                       iap = fec_mac_default;
+       } else {
+               *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
+               *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
+               iap = &tmpaddr[0];
+       }
+
+       for (i=0; i<ETH_ALEN; i++)
+               dev->dev_addr[i] = fep->mac_addr[i] = *iap++;
+
+       /* Adjust MAC if using default MAC address */
+       if (iap == fec_mac_default) {
+               dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] =
+                       iap[ETH_ALEN-1] + fep->index;
+       }
+}
+
+static void __inline__ fec_enable_phy_intr(void)
+{
+}
+
+static void __inline__ fec_disable_phy_intr(void)
+{
+}
+
+static void __inline__ fec_phy_ack_intr(void)
+{
+}
+
+static void __inline__ fec_localhw_setup(void)
+{
+}
+
+/*
+ *     Do not need to make region uncached on 5272.
+ */
+static void __inline__ fec_uncache(unsigned long addr)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+
 #else
 
 /*
  *     Code sepcific to the MPC860T setup.
  */
-static void __inline__ fec_request_intrs(struct net_device *dev, volatile fec_t *fecp)
+static void __inline__ fec_request_intrs(struct net_device *dev)
 {
        volatile immap_t *immap;
 
@@ -1184,13 +1422,13 @@ static void __inline__ fec_request_intrs(struct net_device *dev, volatile fec_t
 #endif
 }
 
-static void __inline__ fec_get_mac(struct net_device *dev, struct fec_enet_private *fep)
+static void __inline__ fec_get_mac(struct net_device *dev)
 {
-       unsigned char *eap, *iap, tmpaddr[6];
+       struct fec_enet_private *fep = netdev_priv(dev);
+       unsigned char *iap, tmpaddr[6];
        bd_t *bd;
        int i;
 
-       eap = (unsigned char *)my_enet_addr;
        iap = bd->bi_enetaddr;
        bd = (bd_t *)__res;
 
@@ -1208,7 +1446,7 @@ static void __inline__ fec_get_mac(struct net_device *dev, struct fec_enet_priva
 #endif
 
        for (i=0; i<6; i++)
-               dev->dev_addr[i] = *eap++ = *iap++;
+               dev->dev_addr[i] = fep->mac_addr[i] = *iap++;
 }
 
 static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
@@ -1217,7 +1455,7 @@ static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_priva
        volatile immap_t *immap;
        volatile fec_t *fecp;
 
-       fecp = fec_hwp;
+       fecp = fep->hwp;
        immap = (immap_t *)IMAP_ADDR;   /* pointer to internal registers */
 
        /* Configure all of port D for MII.
@@ -1240,7 +1478,8 @@ static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_priva
 static void __inline__ fec_enable_phy_intr(void)
 {
        volatile fec_t *fecp;
-       fecp = fec_hwp;
+
+       fecp = fep->hwp;
 
        /* Enable MII command finished interrupt 
        */
@@ -1258,8 +1497,8 @@ static void __inline__ fec_phy_ack_intr(void)
 static void __inline__ fec_localhw_setup(void)
 {
        volatile fec_t *fecp;
-       fecp = fec_hwp;
 
+       fecp = fep->hwp;
        fecp->fec_r_hash = PKT_MAXBUF_SIZE;
        /* Enable big endian and don't care about SDMA FC.
        */
@@ -1319,6 +1558,11 @@ static void mii_display_config(struct net_device *dev)
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile uint *s = &(fep->phy_status);
 
+       /*
+       ** When we get here, phy_task is already removed from
+       ** the workqueue.  It is thus safe to allow to reuse it.
+       */
+       fep->mii_phy_task_queued = 0;
        printk("%s: config: auto-negotiation ", dev->name);
 
        if (*s & PHY_CONF_ANE)
@@ -1350,6 +1594,11 @@ static void mii_relink(struct net_device *dev)
        struct fec_enet_private *fep = netdev_priv(dev);
        int duplex;
 
+       /*
+       ** When we get here, phy_task is already removed from
+       ** the workqueue.  It is thus safe to allow to reuse it.
+       */
+       fep->mii_phy_task_queued = 0;
        fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;
        mii_display_status(dev);
        fep->old_link = fep->link;
@@ -1370,18 +1619,35 @@ static void mii_relink(struct net_device *dev)
 
 }
 
+/* mii_queue_relink is called in interrupt context from mii_link_interrupt */
 static void mii_queue_relink(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
 
+       /*
+       ** We cannot queue phy_task twice in the workqueue.  It
+       ** would cause an endless loop in the workqueue.
+       ** Fortunately, if the last mii_relink entry has not yet been
+       ** executed now, it will do the job for the current interrupt,
+       ** which is just what we want.
+       */
+       if (fep->mii_phy_task_queued)
+               return;
+
+       fep->mii_phy_task_queued = 1;
        INIT_WORK(&fep->phy_task, (void*)mii_relink, dev);
        schedule_work(&fep->phy_task);
 }
 
+/* mii_queue_config is called in user context from fec_enet_open */
 static void mii_queue_config(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
 
+       if (fep->mii_phy_task_queued)
+               return;
+
+       fep->mii_phy_task_queued = 1;
        INIT_WORK(&fep->phy_task, (void*)mii_display_config, dev);
        schedule_work(&fep->phy_task);
 }
@@ -1401,7 +1667,7 @@ static void
 mii_discover_phy3(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep;
-       int     i;
+       int i;
 
        fep = netdev_priv(dev);
        fep->phy_id |= (mii_reg & 0xffff);
@@ -1432,7 +1698,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
        uint phytype;
 
        fep = netdev_priv(dev);
-       fecp = fec_hwp;
+       fecp = fep->hwp;
 
        if (fep->phy_addr < 32) {
                if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) {
@@ -1458,10 +1724,11 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
 
 /* This interrupt occurs when the PHY detects a link change.
 */
-static void
 #ifdef CONFIG_RPXCLASSIC
+static void
 mii_link_interrupt(void *dev_id)
 #else
+static irqreturn_t
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
 #endif
 {
@@ -1477,6 +1744,7 @@ mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
        mii_do_cmd(dev, fep->phy->ack_int);
        mii_do_cmd(dev, phy_cmd_relink);  /* restart and display status */
 
+       return IRQ_HANDLED;
 }
 
 static int
@@ -1487,7 +1755,6 @@ fec_enet_open(struct net_device *dev)
        /* I should reset the ring buffers here, but I don't yet know
         * a simple way to do that.
         */
-
        fec_set_mac_address(dev);
 
        fep->sequence_done = 0;
@@ -1506,6 +1773,12 @@ fec_enet_open(struct net_device *dev)
                        schedule();
 
                mii_do_cmd(dev, fep->phy->startup);
+
+               /* Set the initial link state to true. A lot of hardware
+                * based on this device does not implement a PHY interrupt,
+                * so we are never notified of link change.
+                */
+               fep->link = 1;
        } else {
                fep->link = 1; /* lets just try it and see */
                /* no phy,  go full duplex,  it's most likely a hub chip */
@@ -1513,16 +1786,18 @@ fec_enet_open(struct net_device *dev)
        }
 
        netif_start_queue(dev);
-       opened = 1;
+       fep->opened = 1;
        return 0;               /* Success */
 }
 
 static int
 fec_enet_close(struct net_device *dev)
 {
+       struct fec_enet_private *fep = netdev_priv(dev);
+
        /* Don't know what to do yet.
        */
-       opened = 0;
+       fep->opened = 0;
        netif_stop_queue(dev);
        fec_stop(dev);
 
@@ -1558,7 +1833,7 @@ static void set_multicast_list(struct net_device *dev)
        unsigned char hash;
 
        fep = netdev_priv(dev);
-       ep = fec_hwp;
+       ep = fep->hwp;
 
        if (dev->flags&IFF_PROMISC) {
                /* Log any net taps. */
@@ -1622,18 +1897,18 @@ static void set_multicast_list(struct net_device *dev)
 static void
 fec_set_mac_address(struct net_device *dev)
 {
-       int i;
+       struct fec_enet_private *fep;
        volatile fec_t *fecp;
 
-       fecp = fec_hwp;
-
-       /* Set our copy of the Ethernet address */
-       for (i = 0; i < (ETH_ALEN / 2); i++)
-               my_enet_addr[i] = (dev->dev_addr[i*2] << 8) | dev->dev_addr[i*2 + 1];
+       fep = netdev_priv(dev);
+       fecp = fep->hwp;
 
        /* Set station address. */
-       fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1];
-       fecp->fec_addr_high = my_enet_addr[2] << 16;
+       fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) |
+               (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24);
+       fecp->fec_addr_high = (fep->mac_addr[5] << 16) |
+               (fep->mac_addr[4] << 24);
+
 }
 
 /* Initialize the FEC Ethernet on 860T (or ColdFire 5272).
@@ -1649,14 +1924,18 @@ int __init fec_enet_init(struct net_device *dev)
        cbd_t           *cbd_base;
        volatile fec_t  *fecp;
        int             i, j;
+       static int      index = 0;
 
        /* Only allow us to be probed once. */
-       if (found)
-               return(-ENXIO);
+       if (index >= FEC_MAX_PORTS)
+               return -ENXIO;
 
        /* Create an Ethernet device instance.
        */
-       fecp = fec_hwp;
+       fecp = (volatile fec_t *) fec_hw[index];
+
+       fep->index = index;
+       fep->hwp = fecp;
 
        /* Whack a reset.  We should wait for this.
        */
@@ -1679,7 +1958,7 @@ int __init fec_enet_init(struct net_device *dev)
         * This is our default MAC address unless the user changes
         * it via eth_mac_addr (our dev->set_mac_addr handler).
         */
-       fec_get_mac(dev, fep);
+       fec_get_mac(dev);
 
        /* Allocate memory for buffer descriptors.
        */
@@ -1734,7 +2013,15 @@ int __init fec_enet_init(struct net_device *dev)
        /* ...and the same for transmmit.
        */
        bdp = fep->tx_bd_base;
-       for (i=0; i<TX_RING_SIZE; i++) {
+       for (i=0, j=FEC_ENET_TX_FRPPG; i<TX_RING_SIZE; i++) {
+               if (j >= FEC_ENET_TX_FRPPG) {
+                       mem_addr = __get_free_page(GFP_KERNEL);
+                       j = 1;
+               } else {
+                       mem_addr += FEC_ENET_TX_FRSIZE;
+                       j++;
+               }
+               fep->tx_bounce[i] = (unsigned char *) mem_addr;
 
                /* Initialize the BD for every fragment in the page.
                */
@@ -1756,7 +2043,7 @@ int __init fec_enet_init(struct net_device *dev)
        /* Install our interrupt handlers. This varies depending on
         * the architecture.
        */
-       fec_request_intrs(dev, fecp);
+       fec_request_intrs(dev);
 
        dev->base_addr = (unsigned long)fecp;
 
@@ -1788,7 +2075,7 @@ int __init fec_enet_init(struct net_device *dev)
        fep->phy_addr = 0;
        mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);
 
-       found++;
+       index++;
        return 0;
 }
 
@@ -1800,14 +2087,12 @@ static void
 fec_restart(struct net_device *dev, int duplex)
 {
        struct fec_enet_private *fep;
-       int i;
-       unsigned char *eap;
        volatile cbd_t *bdp;
        volatile fec_t *fecp;
-
-       fecp = fec_hwp;
+       int i;
 
        fep = netdev_priv(dev);
+       fecp = fep->hwp;
 
        /* Whack a reset.  We should wait for this.
        */
@@ -1826,12 +2111,13 @@ fec_restart(struct net_device *dev, int duplex)
 
        /* Set station address.
        */
-       fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1];
-       fecp->fec_addr_high = (my_enet_addr[2] << 16);
+       fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) |
+               (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24);
+       fecp->fec_addr_high = (fep->mac_addr[5] << 16) |
+               (fep->mac_addr[4] << 24);
 
-       eap = (unsigned char *)&my_enet_addr[0];
-       for (i=0; i<6; i++)
-               dev->dev_addr[i] = *eap++;
+       for (i=0; i<ETH_ALEN; i++)
+               dev->dev_addr[i] = fep->mac_addr[i];
 
        /* Reset all multicast.
        */
@@ -1898,11 +2184,12 @@ fec_restart(struct net_device *dev, int duplex)
        /* Enable MII mode.
        */
        if (duplex) {
-               fecp->fec_r_cntrl = 0x04;       /* MII enable */
-               fecp->fec_x_cntrl = 0x04;       /* FD enable */
+               fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;/* MII enable */
+               fecp->fec_x_cntrl = 0x04;                 /* FD enable */
        }
        else {
-               fecp->fec_r_cntrl = 0x06;       /* MII enable|No Rcv on Xmit */
+               /* MII enable|No Rcv on Xmit */
+               fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x06;
                fecp->fec_x_cntrl = 0x00;
        }
        fep->full_duplex = duplex;
@@ -1923,8 +2210,8 @@ fec_stop(struct net_device *dev)
        volatile fec_t *fecp;
        struct fec_enet_private *fep;
 
-       fecp = fec_hwp;
        fep = netdev_priv(dev);
+       fecp = fep->hwp;
 
        fecp->fec_x_cntrl = 0x01;       /* Graceful transmit stop */
 
@@ -1944,29 +2231,27 @@ fec_stop(struct net_device *dev)
        fecp->fec_mii_speed = fep->phy_speed;
 }
 
-static struct net_device *fec_dev;
-
 static int __init fec_enet_module_init(void)
 {
        struct net_device *dev;
-       int err;
-
-       dev = alloc_etherdev(sizeof(struct fec_enet_private));
-       if (!dev)
-               return -ENOMEM;
-       err = fec_enet_init(dev);
-       if (err) {
-               free_netdev(dev);
-               return err;
-       }
-
-       if (register_netdev(dev) != 0) {
-               /* XXX: missing cleanup here */
-               free_netdev(dev);
-               return -EIO;
+       int i, err;
+
+       for (i = 0; (i < FEC_MAX_PORTS); i++) {
+               dev = alloc_etherdev(sizeof(struct fec_enet_private));
+               if (!dev)
+                       return -ENOMEM;
+               err = fec_enet_init(dev);
+               if (err) {
+                       free_netdev(dev);
+                       continue;
+               }
+               if (register_netdev(dev) != 0) {
+                       /* XXX: missing cleanup here */
+                       free_netdev(dev);
+                       return -EIO;
+               }
        }
-       fec_dev = dev;
-       return(0);
+       return 0;
 }
 
 module_init(fec_enet_module_init);
index 3bdb0d7..c6e4f97 100644 (file)
@@ -1,8 +1,8 @@
 /****************************************************************************/
 
 /*
- *     fec.h  --  Fast Ethernet Controller for Motorola ColdFire 5272
*                and 5282..
+ *     fec.h  --  Fast Ethernet Controller for Motorola ColdFire 5270,
                 5271, 5272, 5274, 5275, 5280 and 5282.
  *
  *     (C) Copyright 2000-2003, Greg Ungerer (gerg@snapgear.com)
  *     (C) Copyright 2000-2001, Lineo (www.lineo.com)
@@ -13,7 +13,7 @@
 #define        FEC_H
 /****************************************************************************/
 
-#ifdef CONFIG_M5282
+#if defined(CONFIG_M527x) || defined(CONFIG_M528x)
 /*
  *     Just figures, Motorola would have to change the offsets for
  *     registers in the same peripheral device on different models
index 7d73661..29c275e 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/bitops.h>
 
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
 #include <asm/mpc8xx.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/commproc.h>
 
index 1bf15ee..b4f3a9f 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/bitops.h>
 
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
 #include <asm/mpc8xx.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/commproc.h>
 #include <asm/dma-mapping.h>
index 7002336..8fd1495 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/bitops.h>
 
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
 #include <asm/mpc8xx.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/commproc.h>
 
index e6dba56..85a8752 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/module.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
@@ -152,13 +152,13 @@ static void sp_xmit_on_air(unsigned long channel)
 
        if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
                sp->led_state = 0x70;
-               sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+               sp->tty->driver->write(sp->tty, &sp->led_state, 1);
                sp->tx_enable = 1;
-               actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, sp->status2);
+               actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
                sp->xleft -= actual;
                sp->xhead += actual;
                sp->led_state = 0x60;
-               sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+               sp->tty->driver->write(sp->tty, &sp->led_state, 1);
                sp->status2 = 0;
        } else
                sp_start_tx_timer(sp);
@@ -229,13 +229,13 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
         */
        if (sp->duplex == 1) {
                sp->led_state = 0x70;
-               sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+               sp->tty->driver->write(sp->tty, &sp->led_state, 1);
                sp->tx_enable = 1;
-               actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, count);
+               actual = sp->tty->driver->write(sp->tty, sp->xbuff, count);
                sp->xleft = count - actual;
                sp->xhead = sp->xbuff + actual;
                sp->led_state = 0x60;
-               sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+               sp->tty->driver->write(sp->tty, &sp->led_state, 1);
        } else {
                sp->xleft = count;
                sp->xhead = sp->xbuff;
@@ -493,7 +493,7 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
        }
 
        if (sp->tx_enable == 1) {
-               actual = tty->driver->write(tty, 0, sp->xhead, sp->xleft);
+               actual = tty->driver->write(tty, sp->xhead, sp->xleft);
                sp->xleft -= actual;
                sp->xhead += actual;
        }
@@ -652,8 +652,8 @@ static void resync_tnc(unsigned long channel)
        /* resync the TNC */
 
        sp->led_state = 0x60;
-       sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
-       sp->tty->driver->write(sp->tty, 0, &resync_cmd, 1);
+       sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+       sp->tty->driver->write(sp->tty, &resync_cmd, 1);
 
 
        /* Start resync timer again -- the TNC might be still absent */
@@ -669,7 +669,7 @@ static inline int tnc_init(struct sixpack *sp)
 {
        unsigned char inbyte = 0xe8;
 
-       sp->tty->driver->write(sp->tty, 0, &inbyte, 1);
+       sp->tty->driver->write(sp->tty, &inbyte, 1);
 
        del_timer(&sp->resync_t);
        sp->resync_t.data = (unsigned long) sp;
@@ -954,9 +954,9 @@ static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
        } else { /* output watchdog char if idle */
                if ((sp->status2 != 0) && (sp->duplex == 1)) {
                        sp->led_state = 0x70;
-                       sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+                       sp->tty->driver->write(sp->tty, &sp->led_state, 1);
                        sp->tx_enable = 1;
-                       actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, sp->status2);
+                       actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
                        sp->xleft -= actual;
                        sp->xhead += actual;
                        sp->led_state = 0x60;
@@ -966,7 +966,7 @@ static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
        }
 
        /* needed to trigger the TNC watchdog */
-       sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+       sp->tty->driver->write(sp->tty, &sp->led_state, 1);
 
         /* if the state byte has been received, the TNC is present,
            so the resync timer can be reset. */
@@ -996,12 +996,12 @@ static void decode_std_command(unsigned char cmd, struct sixpack *sp)
                        if ((sp->status & SIXP_RX_DCD_MASK) ==
                                SIXP_RX_DCD_MASK) {
                                sp->led_state = 0x68;
-                               sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+                               sp->tty->driver->write(sp->tty, &sp->led_state, 1);
                        }
                } else {
                        sp->led_state = 0x60;
                        /* fill trailing bytes with zeroes */
-                       sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+                       sp->tty->driver->write(sp->tty, &sp->led_state, 1);
                        rest = sp->rx_count;
                        if (rest != 0)
                                 for (i = rest; i <= 3; i++)
index 4bd7c09..77f29fd 100644 (file)
@@ -83,9 +83,9 @@
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
 #include <linux/parport.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 
 /* --------------------------------------------------------------------- */
index e2a28b5..1b8663f 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -379,7 +379,7 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
        }
        
        ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-       actual = ax->tty->driver->write(ax->tty, 0, ax->xbuff, count);
+       actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
        ax->tx_packets++;
        ax->tx_bytes+=actual;
        ax->dev->trans_start = jiffies;
@@ -411,7 +411,7 @@ static void ax25_write_wakeup(struct tty_struct *tty)
                return;
        }
 
-       actual = tty->driver->write(tty, 0, ax->xhead, ax->xleft);
+       actual = tty->driver->write(tty, ax->xhead, ax->xleft);
        ax->xleft -= actual;
        ax->xhead += actual;
 }
@@ -518,7 +518,7 @@ static int ax_open(struct net_device *dev)
 
        ax->flags   &= (1 << AXF_INUSE);      /* Clear ESCAPE & ERROR flags */
 
-       ax->buflock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&ax->buflock);
 
        netif_start_queue(dev);
        return 0;
index 2049556..8da1948 100644 (file)
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/bitops.h>
 
 #include <net/ax25.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 
 #include "z8530.h"
 
index c516e71..acae594 100644 (file)
@@ -50,7 +50,7 @@
 #include <linux/if.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <linux/interrupt.h>
index 965f949..08703d6 100644 (file)
@@ -40,9 +40,7 @@
 
 /* Our private data structure */
 struct hplance_private {
-  struct lance_private lance;
-  unsigned int scode;
-  void *base;
+       struct lance_private lance;
 };
 
 /* function prototypes... This is easy because all the grot is in the
@@ -50,89 +48,96 @@ struct hplance_private {
  * plus board-specific init, open and close actions. 
  * Oh, and we need to tell the generic code how to read and write LANCE registers...
  */
-static void hplance_init(struct net_device *dev, int scode);
-static int hplance_open(struct net_device *dev);
-static int hplance_close(struct net_device *dev);
+static int __devinit hplance_init_one(struct dio_dev *d,
+                               const struct dio_device_id *ent);
+static void __devinit hplance_init(struct net_device *dev, 
+                               struct dio_dev *d);
+static void __devexit hplance_remove_one(struct dio_dev *d);
 static void hplance_writerap(void *priv, unsigned short value);
 static void hplance_writerdp(void *priv, unsigned short value);
 static unsigned short hplance_readrdp(void *priv);
+static int hplance_open(struct net_device *dev);
+static int hplance_close(struct net_device *dev);
 
-#ifdef MODULE
-static struct hplance_private *root_hplance_dev;
-#endif
+static struct dio_device_id hplance_dio_tbl[] = {
+       { DIO_ID_LAN },
+       { 0 }
+};
 
-static void cleanup_card(struct net_device *dev)
-{
-        struct hplance_private *lp = netdev_priv(dev);
-       dio_unconfig_board(lp->scode);
-}
+static struct dio_driver hplance_driver = {
+       .name      = "hplance",
+       .id_table  = hplance_dio_tbl,
+       .probe     = hplance_init_one,
+       .remove    = __devexit_p(hplance_remove_one),
+};
 
 /* Find all the HP Lance boards and initialise them... */
-struct net_device * __init hplance_probe(int unit)
+static int __devinit hplance_init_one(struct dio_dev *d,
+                               const struct dio_device_id *ent)
 {
        struct net_device *dev;
-
-        if (!MACH_IS_HP300)
-                return ERR_PTR(-ENODEV);
+       int err = -ENOMEM;
 
        dev = alloc_etherdev(sizeof(struct hplance_private));
        if (!dev)
-               return ERR_PTR(-ENOMEM);
+               goto out;
 
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-       }
+       err = -EBUSY;
+       if (!request_mem_region(dio_resource_start(d),
+                               dio_resource_len(d), d->name))
+               goto out_free_netdev;
 
-       SET_MODULE_OWNER(dev);
-        
-        /* Isn't DIO nice? */
-        for(;;)
-        {
-                int scode = dio_find(DIO_ID_LAN);
-                                
-                if (!scode)
-                        break;
-                
-               dio_config_board(scode);
-                hplance_init(dev, scode);
-               if (!register_netdev(dev)) {
-                       struct hplance_private *lp = netdev_priv(dev);
-                       lp->next_module = root_hplance_dev;
-                       root_hplance_dev = lp;
-                       return dev;
-               }
-               cleanup_card(dev);
-        }
+       hplance_init(dev, d);
+       err = register_netdev(dev);
+       if (err)
+               goto out_release_mem_region;
+
+       dio_set_drvdata(d, dev);
+       return 0;
+
+ out_release_mem_region:
+       release_mem_region(dio_resource_start(d), dio_resource_len(d));
+ out_free_netdev:
        free_netdev(dev);
-       return ERR_PTR(-ENODEV);
+ out:
+       return err;
 }
 
-/* Initialise a single lance board at the given select code */
-static void __init hplance_init(struct net_device *dev, int scode)
+static void __devexit hplance_remove_one(struct dio_dev *d)
 {
-        const char *name = dio_scodetoname(scode);
-        void *va = dio_scodetoviraddr(scode);
+       struct net_device *dev = dio_get_drvdata(d);
+
+       unregister_netdev(dev);
+       release_mem_region(dio_resource_start(d), dio_resource_len(d));
+       free_netdev(dev);
+}
+
+/* Initialise a single lance board at the given DIO device */
+static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
+{
+        unsigned long va = (d->resource.start + DIO_VIRADDRBASE);
         struct hplance_private *lp;
         int i;
         
-        printk("%s: %s; select code %d, addr", dev->name, name, scode);
+        printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, d->name, d->scode);
 
         /* reset the board */
         out_8(va+DIO_IDOFF, 0xff);
         udelay(100);                              /* ariba! ariba! udelay! udelay! */
 
         /* Fill the dev fields */
-        dev->base_addr = (unsigned long)va;
+        dev->base_addr = va;
         dev->open = &hplance_open;
         dev->stop = &hplance_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+        dev->poll_controller = lance_poll;
+#endif
         dev->hard_start_xmit = &lance_start_xmit;
         dev->get_stats = &lance_get_stats;
         dev->set_multicast_list = &lance_set_multicast;
         dev->dma = 0;
         
-        for (i=0; i<6; i++)
-        {
+        for (i=0; i<6; i++) {
                 /* The NVRAM holds our ethernet address, one nibble per byte,
                  * at bytes NVRAMOFF+1,3,5,7,9...
                  */
@@ -142,12 +147,12 @@ static void __init hplance_init(struct net_device *dev, int scode)
         }
         
         lp = netdev_priv(dev);
-        lp->lance.name = (char*)name;                   /* discards const, shut up gcc */
-        lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF);
+        lp->lance.name = (char*)d->name;                /* discards const, shut up gcc */
+        lp->lance.base = va;
         lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
         lp->lance.lance_init_block = 0;                 /* LANCE addr of same RAM */
         lp->lance.busmaster_regval = LE_C3_BSWP;        /* we're bigendian */
-        lp->lance.irq = dio_scodetoipl(scode);
+        lp->lance.irq = d->ipl;
         lp->lance.writerap = hplance_writerap;
         lp->lance.writerdp = hplance_writerdp;
         lp->lance.readrdp = hplance_readrdp;
@@ -155,8 +160,6 @@ static void __init hplance_init(struct net_device *dev, int scode)
         lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
         lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
         lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
-        lp->scode = scode;
-       lp->base = va;
        printk(", irq %d\n", lp->lance.irq);
 }
 
@@ -165,78 +168,64 @@ static void __init hplance_init(struct net_device *dev, int scode)
  */
 static void hplance_writerap(void *priv, unsigned short value)
 {
-       struct hplance_private *lp = (struct hplance_private *)priv;
-        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
-        do {
-                lp->lance.ll->rap = value;
-        } while ((hpregs->status & LE_ACK) == 0);
+       struct lance_private *lp = (struct lance_private *)priv;
+       do {
+               out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value);
+       } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
 }
 
 static void hplance_writerdp(void *priv, unsigned short value)
 {
-       struct hplance_private *lp = (struct hplance_private *)priv;
-        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
-        do {
-                lp->lance.ll->rdp = value;
-        } while ((hpregs->status & LE_ACK) == 0);
+       struct lance_private *lp = (struct lance_private *)priv;
+       do {
+               out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value);
+       } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
 }
 
 static unsigned short hplance_readrdp(void *priv)
 {
-        unsigned short val;
-       struct hplance_private *lp = (struct hplance_private *)priv;
-        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
-        do {
-                val = lp->lance.ll->rdp;
-        } while ((hpregs->status & LE_ACK) == 0);
-        return val;
+       struct lance_private *lp = (struct lance_private *)priv;
+       __u16 value;
+       do {
+               value = in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP);
+       } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
+       return value;
 }
 
 static int hplance_open(struct net_device *dev)
 {
         int status;
-        struct hplance_private *lp = netdev_priv(dev);
-        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        struct lance_private *lp = netdev_priv(dev);
         
         status = lance_open(dev);                 /* call generic lance open code */
         if (status)
                 return status;
         /* enable interrupts at board level. */
-        out_8(&(hpregs->status), LE_IE);
+        out_8(lp->base + HPLANCE_STATUS, LE_IE);
 
         return 0;
 }
 
 static int hplance_close(struct net_device *dev)
 {
-        struct hplance_private *lp = netdev_priv(dev);
-        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
-        out_8(&(hpregs->status), 8);              /* disable interrupts at boardlevel */
+        struct lance_private *lp = netdev_priv(dev);
+
+        out_8(lp->base + HPLANCE_STATUS, 0);   /* disable interrupts at boardlevel */
         lance_close(dev);
         return 0;
 }
 
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-int init_module(void)
+int __init hplance_init_module(void)
 {
-       int found = 0;
-       while (!IS_ERR(hplance_probe(-1)))
-               found++;
-       return found ? 0 : -ENODEV;
+       return dio_module_init(&hplance_driver);
 }
 
-void cleanup_module(void)
+void __exit hplance_cleanup_module(void)
 {
-        /* Walk the chain of devices, unregistering them */
-        struct hplance_private *lp;
-        while (root_hplance_dev) {
-                lp = root_hplance_dev->next_module;
-                unregister_netdev(root_lance_dev->dev);
-                cleanup_card(root_lance_dev->dev);
-                free_netdev(root_lance_dev->dev);
-                root_lance_dev = lp;
-        }
+        dio_unregister_driver(&hplance_driver);
 }
 
-#endif /* MODULE */
+module_init(hplance_init_module);
+module_exit(hplance_cleanup_module);
+
+MODULE_LICENSE("GPL");
index 3af4c4d..04aee9e 100644 (file)
@@ -4,15 +4,10 @@
  */
 
 /* Registers */
-struct hplance_reg
-{
-        u_char pad0;
-        volatile u_char id;                       /* DIO register: ID byte */
-        u_char pad1;
-        volatile u_char status;                   /* DIO register: interrupt enable */
-};
+#define HPLANCE_ID             0x01            /* DIO register: ID byte */
+#define HPLANCE_STATUS         0x03            /* DIO register: interrupt enable/status */
 
-/* Control and status bits for the hplance->status register */
+/* Control and status bits for the status register */
 #define LE_IE 0x80                                /* interrupt enable */
 #define LE_IR 0x40                                /* interrupt requested */
 #define LE_LOCK 0x08                              /* lock status register */
@@ -25,7 +20,7 @@ struct hplance_reg
 /* These are the offsets for the DIO regs (hplance_reg), lance_ioreg,
  * memory and NVRAM:
  */
-#define HPLANCE_IDOFF 0                           /* board baseaddr, struct hplance_reg */
-#define HPLANCE_REGOFF 0x4000                     /* struct lance_regs */
+#define HPLANCE_IDOFF 0                           /* board baseaddr */
+#define HPLANCE_REGOFF 0x4000                     /* lance registers */
 #define HPLANCE_MEMOFF 0x8000                     /* struct lance_init_block */
 #define HPLANCE_NVRAMOFF 0xC008                   /* etheraddress as one *nibble* per byte */
index fecaec1..6e0ca73 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/amigaints.h>
index 6b0328f..39c6506 100644 (file)
@@ -40,9 +40,9 @@
 #include <linux/dma-mapping.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/bitops.h>
 
 #include <asm/processor.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
@@ -620,7 +620,7 @@ emac_rx_csum(struct net_device *dev, unsigned short ctrl, struct sk_buff *skb)
 
 static int emac_rx_clean(struct net_device *dev)
 {
-       int i, b, bnum, buf[6];
+       int i, b, bnum = 0, buf[6];
        int error, frame_length;
        struct ocp_enet_private *fep = dev->priv;
        unsigned short ctrl;
@@ -1021,7 +1021,6 @@ static int emac_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static int emac_adjust_to_link(struct ocp_enet_private *fep)
 {
        emac_t *emacp = fep->emacp;
-       struct ibm_ocp_rgmii *rgmii;
        unsigned long mode_reg;
        int full_duplex, speed;
 
@@ -1038,21 +1037,23 @@ static int emac_adjust_to_link(struct ocp_enet_private *fep)
                speed = fep->phy_mii.speed;
        }
 
-       if (fep->rgmii_dev)
-               rgmii = RGMII_PRIV(fep->rgmii_dev);
 
        /* set speed (default is 10Mb) */
        switch (speed) {
        case SPEED_1000:
                mode_reg |= EMAC_M1_JUMBO_ENABLE | EMAC_M1_RFS_16K;
-               if ((rgmii->mode[fep->rgmii_input] == RTBI)
-                   || (rgmii->mode[fep->rgmii_input] == TBI))
-                       mode_reg |= EMAC_M1_MF_1000GPCS;
-               else
-                       mode_reg |= EMAC_M1_MF_1000MBPS;
-               if (fep->rgmii_dev)
+               if (fep->rgmii_dev) {
+                       struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(fep->rgmii_dev);
+
+                       if ((rgmii->mode[fep->rgmii_input] == RTBI)
+                           || (rgmii->mode[fep->rgmii_input] == TBI))
+                               mode_reg |= EMAC_M1_MF_1000GPCS;
+                       else
+                               mode_reg |= EMAC_M1_MF_1000MBPS;
+
                        emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input,
                                              1000);
+               }
                break;
        case SPEED_100:
                mode_reg |= EMAC_M1_MF_100MBPS | EMAC_M1_RFS_4K;
index 8e456ce..dd9f0da 100644 (file)
@@ -83,6 +83,7 @@ struct ibm_ocp_mal {
                GET_MAL0_STANZA(dcrn) \
                GET_MAL1_STANZA(dcrn) \
        default: \
+               x = 0; \
                BUG(); \
        } \
 x; })
index c5af0cb..a02a2a2 100644 (file)
@@ -28,9 +28,9 @@
 #include <linux/rtnetlink.h>
 #include <linux/interrupt.h>
 #include <linux/pm.h>
+#include <linux/bitops.h>
 
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/au1000.h>
 #if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100)
index c4b7b2a..89f5096 100644 (file)
 #include <asm/irq.h>
 #include <asm/dma.h>
 #include <asm/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/arch/assabet.h>
-#include <asm/arch/h3600.h>
-#include <asm/arch/yopy.h>
-
-#ifndef GPIO_IRDA_FIR
-#define GPIO_IRDA_FIR          (0)
-#endif
-
-#ifndef GPIO_IRDA_POWER
-#define GPIO_IRDA_POWER                (0)
-#endif
+#include <asm/mach/irda.h>
 
 static int power_level = 3;
 static int tx_lpm;
@@ -75,6 +63,7 @@ struct sa1100_irda {
 
        struct net_device_stats stats;
        struct device           *dev;
+       struct irda_platform_data *pdata;
        struct irlap_cb         *irlap;
        struct qos_info         qos;
 
@@ -170,12 +159,8 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
                Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
                Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
 
-               if (machine_is_assabet())
-                       ASSABET_BCR_clear(ASSABET_BCR_IRDA_FSEL);
-               if (machine_is_h3xxx())
-                       clr_h3600_egpio(IPAQ_EGPIO_IR_FSEL);
-               if (machine_is_yopy())
-                       PPSR &= ~GPIO_IRDA_FIR;
+               if (si->pdata->set_speed)
+                       si->pdata->set_speed(si->dev, speed);
 
                si->speed = speed;
 
@@ -194,12 +179,8 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 
                si->speed = speed;
 
-               if (machine_is_assabet())
-                       ASSABET_BCR_set(ASSABET_BCR_IRDA_FSEL);
-               if (machine_is_h3xxx())
-                       set_h3600_egpio(IPAQ_EGPIO_IR_FSEL);
-               if (machine_is_yopy())
-                       PPSR |= GPIO_IRDA_FIR;
+               if (si->pdata->set_speed)
+                       si->pdata->set_speed(si->dev, speed);
 
                sa1100_irda_rx_alloc(si);
                sa1100_irda_rx_dma_start(si);
@@ -215,51 +196,6 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
        return ret;
 }
 
-/*
- * This sets the IRDA power level on the Assabet.
- */
-static inline int
-sa1100_irda_set_power_assabet(struct sa1100_irda *si, unsigned int state)
-{
-       static unsigned int bcr_state[4] = {
-               ASSABET_BCR_IRDA_MD0,
-               ASSABET_BCR_IRDA_MD1|ASSABET_BCR_IRDA_MD0,
-               ASSABET_BCR_IRDA_MD1,
-               0
-       };
-
-       if (state < 4) {
-               state = bcr_state[state];
-               ASSABET_BCR_clear(state ^ (ASSABET_BCR_IRDA_MD1|
-                                          ASSABET_BCR_IRDA_MD0));
-               ASSABET_BCR_set(state);
-       }
-       return 0;
-}
-
-/*
- * This turns the IRDA power on or off on the Compaq H3600
- */
-static inline int
-sa1100_irda_set_power_h3600(struct sa1100_irda *si, unsigned int state)
-{
-       assign_h3600_egpio( IPAQ_EGPIO_IR_ON, state );
-       return 0;
-}
-
-/*
- * This turns the IRDA power on or off on the Yopy
- */
-static inline int
-sa1100_irda_set_power_yopy(struct sa1100_irda *si, unsigned int state)
-{
-       if (state)
-               PPSR &= ~GPIO_IRDA_POWER;
-       else
-               PPSR |= GPIO_IRDA_POWER;
-       return 0;
-}
-
 /*
  * Control the power state of the IrDA transmitter.
  * State:
@@ -274,14 +210,8 @@ static int
 __sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state)
 {
        int ret = 0;
-
-       if (machine_is_assabet())
-               ret = sa1100_irda_set_power_assabet(si, state);
-       if (machine_is_h3xxx())
-               ret = sa1100_irda_set_power_h3600(si, state);
-       if (machine_is_yopy())
-               ret = sa1100_irda_set_power_yopy(si, state);
-
+       if (si->pdata->set_power)
+               ret = si->pdata->set_power(si->dev, state);
        return ret;
 }
 
@@ -304,11 +234,8 @@ static int sa1100_irda_startup(struct sa1100_irda *si)
        /*
         * Ensure that the ports for this device are setup correctly.
         */
-       if (machine_is_yopy()) {
-               PPDR |= GPIO_IRDA_POWER | GPIO_IRDA_FIR;
-               PPSR |= GPIO_IRDA_POWER | GPIO_IRDA_FIR;
-               PSDR |= GPIO_IRDA_POWER | GPIO_IRDA_FIR;
-       }
+       if (si->pdata->startup)
+               si->pdata->startup(si->dev);
 
        /*
         * Configure PPC for IRDA - we want to drive TXD2 low.
@@ -333,10 +260,15 @@ static int sa1100_irda_startup(struct sa1100_irda *si)
        Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
 
        ret = sa1100_irda_set_speed(si, si->speed = 9600);
-       if (ret)
-               return ret;
+       if (ret) {
+               Ser2UTCR3 = 0;
+               Ser2HSCR0 = 0;
 
-       return 0;
+               if (si->pdata->shutdown)
+                       si->pdata->shutdown(si->dev);
+       }
+
+       return ret;
 }
 
 static void sa1100_irda_shutdown(struct sa1100_irda *si)
@@ -350,6 +282,9 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si)
        /* Disable the port. */
        Ser2UTCR3 = 0;
        Ser2HSCR0 = 0;
+
+       if (si->pdata->shutdown)
+               si->pdata->shutdown(si->dev);
 }
 
 #ifdef CONFIG_PM
@@ -959,6 +894,9 @@ static int sa1100_irda_probe(struct device *_dev)
        unsigned int baudrate_mask;
        int err;
 
+       if (!pdev->dev.platform_data)
+               return -EINVAL;
+
        err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY;
        if (err)
                goto err_mem_1;
@@ -975,6 +913,7 @@ static int sa1100_irda_probe(struct device *_dev)
 
        si = dev->priv;
        si->dev = &pdev->dev;
+       si->pdata = pdev->dev.platform_data;
 
        /*
         * Initialise the HP-SIR buffers
@@ -1028,7 +967,7 @@ static int sa1100_irda_probe(struct device *_dev)
 
        err = register_netdev(dev);
        if (err == 0)
-               dev_set_drvdata(&pdev->dev, si);
+               dev_set_drvdata(&pdev->dev, dev);
 
        if (err) {
  err_mem_5:
@@ -1074,15 +1013,8 @@ static struct device_driver sa1100ir_driver = {
        .resume         = sa1100_irda_resume,
 };
 
-static struct platform_device sa1100ir_device = {
-       .name           = "sa11x0-ir",
-       .id             = 0,
-};
-
 static int __init sa1100_irda_init(void)
 {
-       int ret;
-
        /*
         * Limit power level a sensible range.
         */
@@ -1091,19 +1023,12 @@ static int __init sa1100_irda_init(void)
        if (power_level > 3)
                power_level = 3;
 
-       ret = driver_register(&sa1100ir_driver);
-       if (ret == 0) {
-               ret = platform_device_register(&sa1100ir_device);
-               if (ret)
-                       driver_unregister(&sa1100ir_driver);
-       }
-       return ret;
+       return driver_register(&sa1100ir_driver);
 }
 
 static void __exit sa1100_irda_exit(void)
 {
        driver_unregister(&sa1100ir_driver);
-       platform_device_unregister(&sa1100ir_device);
 }
 
 module_init(sa1100_irda_init);
index 55e4a7f..1e947e6 100644 (file)
@@ -769,7 +769,6 @@ typedef struct vlsi_irda_dev {
        spinlock_t              lock;
        struct semaphore        sem;
 
-       u32                     cfg_space[64/sizeof(u32)];
        u8                      resume_ok;      
        struct proc_dir_entry   *proc_entry;
 
index 0a8094e..ce57618 100644 (file)
@@ -32,9 +32,9 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/hwtest.h>
 
 #include "8390.h"
 
-#if (LINUX_VERSION_CODE < 0x02030e)
-#define net_device device
-#endif
-
 #define WD_START_PG                    0x00    /* First page of TX buffer */
 #define CABLETRON_RX_START_PG          0x00    /* First page of RX buffer */
 #define CABLETRON_RX_STOP_PG           0x30    /* Last page +1 of RX ring */
index 8c08255..f65b0db 100644 (file)
@@ -98,6 +98,7 @@ static char *version =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -308,8 +309,7 @@ void __init reset_chip(struct net_device *dev)
        writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
 
        /* wait 30 ms */
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(30*HZ/1000);
+       msleep_interruptible(30);
 
        /* Wait until the chip is reset */
        reset_start_time = jiffies;
index 619a67a..2c0f2aa 100644 (file)
@@ -367,31 +367,6 @@ static int meth_release(struct net_device *dev)
        return 0;
 }
 
-/*
- * Configuration changes (passed on by ifconfig)
- */
-static int meth_config(struct net_device *dev, struct ifmap *map)
-{
-       if (dev->flags & IFF_UP) /* can't act on a running interface */
-               return -EBUSY;
-
-       /* Don't allow changing the I/O address */
-       if (map->base_addr != dev->base_addr) {
-               printk(KERN_WARNING "meth: Can't change I/O address\n");
-               return -EOPNOTSUPP;
-       }
-
-       /* Don't allow changing the IRQ */
-       if (map->irq != dev->irq) {
-               printk(KERN_WARNING "meth: Can't change IRQ\n");
-               return -EOPNOTSUPP;
-       }
-       DPRINTK("Configured\n");
-
-       /* ignore other fields */
-       return 0;
-}
-
 /*
  * Receive a packet: retrieve, encapsulate and pass over to upper levels
  */
@@ -813,7 +788,6 @@ static struct net_device *meth_init(void)
 
        dev->open            = meth_open;
        dev->stop            = meth_release;
-       dev->set_config      = meth_config;
        dev->hard_start_xmit = meth_tx;
        dev->do_ioctl        = meth_ioctl;
        dev->get_stats       = meth_stats;
index 41d38b3..362fee3 100644 (file)
@@ -49,7 +49,7 @@
 #include <linux/etherdevice.h>
 #include <net/ip.h>
 
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/io.h>
 #include <asm/types.h>
 #include <asm/pgtable.h>
index 5995658..56a82d8 100644 (file)
@@ -18,7 +18,6 @@
 /* Used for the temporal inet entries and routing */
 #include <linux/socket.h>
 #include <linux/route.h>
-#include <linux/dio.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
@@ -40,7 +39,6 @@
 /* Our private data structure */
 struct m147lance_private {
        struct lance_private lance;
-       void *base;
        unsigned long ram;
 };
 
@@ -51,9 +49,9 @@ struct m147lance_private {
  */
 static int m147lance_open(struct net_device *dev);
 static int m147lance_close(struct net_device *dev);
-static void m147lance_writerap(struct m147lance_private *lp, unsigned short value);
-static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value);
-static unsigned short m147lance_readrdp(struct m147lance_private *lp);
+static void m147lance_writerap(struct lance_private *lp, unsigned short value);
+static void m147lance_writerdp(struct lance_private *lp, unsigned short value);
+static unsigned short m147lance_readrdp(struct lance_private *lp);
 
 typedef void (*writerap_t)(void *, unsigned short);
 typedef void (*writerdp_t)(void *, unsigned short);
@@ -122,7 +120,7 @@ struct net_device * __init mvme147lance_probe(int unit)
        }
 
        lp->lance.name = (char*)name;                   /* discards const, shut up gcc */
-       lp->lance.ll = (struct lance_regs *)(dev->base_addr);
+       lp->lance.base = dev->base_addr;
        lp->lance.init_block = (struct lance_init_block *)(lp->ram); /* CPU addr */
        lp->lance.lance_init_block = (struct lance_init_block *)(lp->ram);                 /* LANCE addr of same RAM */
        lp->lance.busmaster_regval = LE_C3_BSWP;        /* we're bigendian */
@@ -145,19 +143,19 @@ struct net_device * __init mvme147lance_probe(int unit)
        return dev;
 }
 
-static void m147lance_writerap(struct m147lance_private *lp, unsigned short value)
+static void m147lance_writerap(struct lance_private *lp, unsigned short value)
 {
-       lp->lance.ll->rap = value;
+       out_be16(lp->base + LANCE_RAP, value);
 }
 
-static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value)
+static void m147lance_writerdp(struct lance_private *lp, unsigned short value)
 {
-       lp->lance.ll->rdp = value;
+       out_be16(lp->base + LANCE_RDP, value);
 }
 
-static unsigned short m147lance_readrdp(struct m147lance_private *lp)
+static unsigned short m147lance_readrdp(struct lance_private *lp)
 {
-       return lp->lance.ll->rdp;
+       return in_be16(lp->base + LANCE_RDP);
 }
 
 static int m147lance_open(struct net_device *dev)
index c5f9595..d85e04b 100644 (file)
@@ -22,6 +22,7 @@ static char version[] =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 
 #include <net/dst.h>
 #include <net/arp.h>
@@ -29,7 +30,6 @@ static char version[] =
 #include <net/ipv6.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
index 854bc2b..1f9e0dd 100644 (file)
@@ -105,260 +105,6 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *mask,
 }
 EXPORT_SYMBOL(alloc_netdev);
 
-/**
- * alloc_etherdev - Allocates and sets up an ethernet device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- *     for this ethernet device
- *
- * Fill in the fields of the device structure with ethernet-generic
- * values. Basically does everything except registering the device.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
-
-struct net_device *alloc_etherdev(int sizeof_priv)
-{
-       return alloc_netdev(sizeof_priv, "eth%d", ether_setup);
-}
-
-EXPORT_SYMBOL(alloc_etherdev);
-
-static int eth_mac_addr(struct net_device *dev, void *p)
-{
-       struct sockaddr *addr=p;
-       if (netif_running(dev))
-               return -EBUSY;
-       memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
-       return 0;
-}
-
-static int eth_change_mtu(struct net_device *dev, int new_mtu)
-{
-       if ((new_mtu < 68) || (new_mtu > 1500))
-               return -EINVAL;
-       dev->mtu = new_mtu;
-       return 0;
-}
-
-#ifdef CONFIG_FDDI
-
-/**
- * alloc_fddidev - Register FDDI device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- *     for this FDDI device
- *
- * Fill in the fields of the device structure with FDDI-generic values.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
-
-struct net_device *alloc_fddidev(int sizeof_priv)
-{
-       return alloc_netdev(sizeof_priv, "fddi%d", fddi_setup);
-}
-
-EXPORT_SYMBOL(alloc_fddidev);
-
-static int fddi_change_mtu(struct net_device *dev, int new_mtu)
-{
-       if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN))
-               return(-EINVAL);
-       dev->mtu = new_mtu;
-       return(0);
-}
-
-#endif /* CONFIG_FDDI */
-
-#ifdef CONFIG_HIPPI
-
-static int hippi_change_mtu(struct net_device *dev, int new_mtu)
-{
-       /*
-        * HIPPI's got these nice large MTUs.
-        */
-       if ((new_mtu < 68) || (new_mtu > 65280))
-               return -EINVAL;
-       dev->mtu = new_mtu;
-       return(0);
-}
-
-
-/*
- * For HIPPI we will actually use the lower 4 bytes of the hardware
- * address as the I-FIELD rather than the actual hardware address.
- */
-static int hippi_mac_addr(struct net_device *dev, void *p)
-{
-       struct sockaddr *addr = p;
-       if (netif_running(dev))
-               return -EBUSY;
-       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       return 0;
-}
-
-static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
-{
-       /* Never send broadcast/multicast ARP messages */
-       p->mcast_probes = 0;
-       /* In IPv6 unicast probes are valid even on NBMA,
-       * because they are encapsulated in normal IPv6 protocol.
-       * Should be a generic flag. 
-       */
-       if (p->tbl->family != AF_INET6)
-               p->ucast_probes = 0;
-       return 0;
-}
-
-static void hippi_setup(struct net_device *dev)
-{
-       dev->set_multicast_list = NULL;
-       dev->change_mtu                 = hippi_change_mtu;
-       dev->hard_header                = hippi_header;
-       dev->rebuild_header             = hippi_rebuild_header;
-       dev->set_mac_address            = hippi_mac_addr;
-       dev->hard_header_parse          = NULL;
-       dev->hard_header_cache          = NULL;
-       dev->header_cache_update        = NULL;
-       dev->neigh_setup                = hippi_neigh_setup_dev; 
-
-       /*
-        * We don't support HIPPI `ARP' for the time being, and probably
-        * never will unless someone else implements it. However we
-        * still need a fake ARPHRD to make ifconfig and friends play ball.
-        */
-       dev->type               = ARPHRD_HIPPI;
-       dev->hard_header_len    = HIPPI_HLEN;
-       dev->mtu                = 65280;
-       dev->addr_len           = HIPPI_ALEN;
-       dev->tx_queue_len       = 25 /* 5 */;
-       memset(dev->broadcast, 0xFF, HIPPI_ALEN);
-
-
-       /*
-        * HIPPI doesn't support broadcast+multicast and we only use
-        * static ARP tables. ARP is disabled by hippi_neigh_setup_dev. 
-        */
-       dev->flags = 0; 
-}
-
-/**
- * alloc_hippi_dev - Register HIPPI device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- *     for this HIPPI device
- *
- * Fill in the fields of the device structure with HIPPI-generic values.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
-
-struct net_device *alloc_hippi_dev(int sizeof_priv)
-{
-       return alloc_netdev(sizeof_priv, "hip%d", hippi_setup);
-}
-
-EXPORT_SYMBOL(alloc_hippi_dev);
-
-#endif /* CONFIG_HIPPI */
-
-void ether_setup(struct net_device *dev)
-{
-       /* Fill in the fields of the device structure with ethernet-generic values.
-          This should be in a common file instead of per-driver.  */
-       
-       dev->change_mtu         = eth_change_mtu;
-       dev->hard_header        = eth_header;
-       dev->rebuild_header     = eth_rebuild_header;
-       dev->set_mac_address    = eth_mac_addr;
-       dev->hard_header_cache  = eth_header_cache;
-       dev->header_cache_update= eth_header_cache_update;
-       dev->hard_header_parse  = eth_header_parse;
-
-       dev->type               = ARPHRD_ETHER;
-       dev->hard_header_len    = ETH_HLEN;
-       dev->mtu                = 1500; /* eth_mtu */
-       dev->addr_len           = ETH_ALEN;
-       dev->tx_queue_len       = 1000; /* Ethernet wants good queues */        
-       
-       memset(dev->broadcast,0xFF, ETH_ALEN);
-
-       /* New-style flags. */
-       dev->flags              = IFF_BROADCAST|IFF_MULTICAST;
-}
-EXPORT_SYMBOL(ether_setup);
-
-#ifdef CONFIG_FDDI
-
-void fddi_setup(struct net_device *dev)
-{
-       /*
-        * Fill in the fields of the device structure with FDDI-generic values.
-        * This should be in a common file instead of per-driver.
-        */
-       
-       dev->change_mtu                 = fddi_change_mtu;
-       dev->hard_header                = fddi_header;
-       dev->rebuild_header             = fddi_rebuild_header;
-
-       dev->type                               = ARPHRD_FDDI;
-       dev->hard_header_len    = FDDI_K_SNAP_HLEN+3;   /* Assume 802.2 SNAP hdr len + 3 pad bytes */
-       dev->mtu                                = FDDI_K_SNAP_DLEN;             /* Assume max payload of 802.2 SNAP frame */
-       dev->addr_len                   = FDDI_K_ALEN;
-       dev->tx_queue_len               = 100;  /* Long queues on FDDI */
-       
-       memset(dev->broadcast, 0xFF, FDDI_K_ALEN);
-
-       /* New-style flags */
-       dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
-}
-EXPORT_SYMBOL(fddi_setup);
-
-#endif /* CONFIG_FDDI */
-
-#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
-
-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);
-
-#endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */
-
 int register_netdev(struct net_device *dev)
 {
        int err;
@@ -404,90 +150,3 @@ void unregister_netdev(struct net_device *dev)
 
 EXPORT_SYMBOL(register_netdev);
 EXPORT_SYMBOL(unregister_netdev);
-
-#ifdef CONFIG_TR
-
-void tr_setup(struct net_device *dev)
-{
-       /*
-        *      Configure and register
-        */
-       
-       dev->hard_header        = tr_header;
-       dev->rebuild_header     = tr_rebuild_header;
-
-       dev->type               = ARPHRD_IEEE802_TR;
-       dev->hard_header_len    = TR_HLEN;
-       dev->mtu                = 2000;
-       dev->addr_len           = TR_ALEN;
-       dev->tx_queue_len       = 100;  /* Long queues on tr */
-       
-       memset(dev->broadcast,0xFF, TR_ALEN);
-
-       /* New-style flags. */
-       dev->flags              = IFF_BROADCAST | IFF_MULTICAST ;
-}
-
-/**
- * alloc_trdev - Register token ring device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- *     for this token ring device
- *
- * Fill in the fields of the device structure with token ring-generic values.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
-
-struct net_device *alloc_trdev(int sizeof_priv)
-{
-       return alloc_netdev(sizeof_priv, "tr%d", tr_setup);
-}
-
-EXPORT_SYMBOL(tr_setup);
-EXPORT_SYMBOL(alloc_trdev);
-
-#endif /* CONFIG_TR */
-
-#ifdef CONFIG_NET_FC
-
-void fc_setup(struct net_device *dev)
-{
-       dev->hard_header        =        fc_header;
-        dev->rebuild_header    =        fc_rebuild_header;
-                
-        dev->type               =        ARPHRD_IEEE802;
-       dev->hard_header_len    =        FC_HLEN;
-        dev->mtu                =        2024;
-        dev->addr_len           =        FC_ALEN;
-        dev->tx_queue_len       =        100; /* Long queues on fc */
-
-        memset(dev->broadcast,0xFF, FC_ALEN);
-
-        /* New-style flags. */
-        dev->flags              =        IFF_BROADCAST;
-}
-
-/**
- * alloc_fcdev - Register fibre channel device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- *     for this fibre channel device
- *
- * Fill in the fields of the device structure with fibre channel-generic values.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
-
-struct net_device *alloc_fcdev(int sizeof_priv)
-{
-       return alloc_netdev(sizeof_priv, "fc%d", fc_setup);
-}
-
-EXPORT_SYMBOL(fc_setup);
-EXPORT_SYMBOL(alloc_fcdev);
-
-#endif /* CONFIG_NET_FC */
-
index 8124ad6..2ab01a5 100644 (file)
@@ -59,7 +59,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
index c43c4cf..fd58f0d 100644 (file)
@@ -73,8 +73,8 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
index c51291a..df75c94 100644 (file)
@@ -636,7 +636,7 @@ struct compressor ppp_deflate_draft = {
        .owner =                THIS_MODULE
 };
 
-int __init deflate_init(void)
+static int __init deflate_init(void)
 {  
         int answer = ppp_register_compressor(&ppp_deflate);
         if (answer == 0)
@@ -646,7 +646,7 @@ int __init deflate_init(void)
         return answer;
 }
      
-void __exit deflate_cleanup(void)
+static void __exit deflate_cleanup(void)
 {
        ppp_unregister_compressor(&ppp_deflate);
        ppp_unregister_compressor(&ppp_deflate_draft);
index 1049131..10baae5 100644 (file)
@@ -510,7 +510,7 @@ static inline void set_rraddr(rraddr *ra, dma_addr_t addr)
 }
 
 
-static inline void set_rxaddr(struct rr_regs *regs, volatile dma_addr_t addr)
+static inline void set_rxaddr(struct rr_regs __iomem *regs, volatile dma_addr_t addr)
 {
        unsigned long baddr = addr;
 #if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN)
@@ -527,7 +527,7 @@ static inline void set_rxaddr(struct rr_regs *regs, volatile dma_addr_t addr)
 }
 
 
-static inline void set_infoaddr(struct rr_regs *regs, volatile dma_addr_t addr)
+static inline void set_infoaddr(struct rr_regs __iomem *regs, volatile dma_addr_t addr)
 {
        unsigned long baddr = addr;
 #if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN)
@@ -808,7 +808,7 @@ struct rr_private
        /* Alignment ok ? */
        struct sk_buff          *rx_skbuff[RX_RING_ENTRIES];
        struct sk_buff          *tx_skbuff[TX_RING_ENTRIES];
-       struct rr_regs          *regs;          /* Register base */
+       struct rr_regs          __iomem *regs;          /* Register base */
        struct ring_ctrl        *rx_ctrl;       /* Receive ring control */
        struct rr_info          *info;          /* Shared info page */
        dma_addr_t              rx_ctrl_dma;
index 0f237b5..d9fd930 100644 (file)
@@ -45,9 +45,9 @@ static const char version[] =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
index bc71b55..425012d 100644 (file)
@@ -72,10 +72,10 @@ static const char rcsid[] = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $"
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/bitops.h> 
 
 #include "sk_g16.h"
 
index 0c1995b..4ce52f5 100644 (file)
 #define SL_CHECK_TRANSMIT
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
@@ -85,8 +86,8 @@
 
 static struct net_device **slip_devs;
 
-int slip_maxdev = SL_NRUNIT;           /* Can be overridden with insmod! */
-MODULE_PARM(slip_maxdev, "i");
+static int slip_maxdev = SL_NRUNIT;
+module_param(slip_maxdev, int, 0);
 MODULE_PARM_DESC(slip_maxdev, "Maximum number of slip devices");
 
 static int slip_esc(unsigned char *p, unsigned char *d, int len);
@@ -417,7 +418,7 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
         *       14 Oct 1994  Dmitry Gorodchanin.
         */
        sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-       actual = sl->tty->driver->write(sl->tty, 0, sl->xbuff, count);
+       actual = sl->tty->driver->write(sl->tty, sl->xbuff, count);
 #ifdef SL_CHECK_TRANSMIT
        sl->dev->trans_start = jiffies;
 #endif
@@ -451,20 +452,18 @@ static void slip_write_wakeup(struct tty_struct *tty)
                return;
        }
 
-       actual = tty->driver->write(tty, 0, sl->xhead, sl->xleft);
+       actual = tty->driver->write(tty, sl->xhead, sl->xleft);
        sl->xleft -= actual;
        sl->xhead += actual;
 }
 
 static void sl_tx_timeout(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        spin_lock(&sl->lock);
 
        if (netif_queue_stopped(dev)) {
-               struct slip *sl = (struct slip*)(dev->priv);
-
                if (!netif_running(dev))
                        goto out;
 
@@ -494,7 +493,7 @@ out:
 static int
 sl_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        spin_lock(&sl->lock);
        if (!netif_running(dev))  {
@@ -528,7 +527,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
 static int
 sl_close(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        spin_lock_bh(&sl->lock);
        if (sl->tty) {
@@ -547,7 +546,7 @@ sl_close(struct net_device *dev)
 
 static int sl_open(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        if (sl->tty==NULL)
                return -ENODEV;
@@ -561,7 +560,7 @@ static int sl_open(struct net_device *dev)
 
 static int sl_change_mtu(struct net_device *dev, int new_mtu)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        if (new_mtu < 68 || new_mtu > 65534)
                return -EINVAL;
@@ -577,7 +576,7 @@ static struct net_device_stats *
 sl_get_stats(struct net_device *dev)
 {
        static struct net_device_stats stats;
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 #ifdef SL_INCLUDE_CSLIP
        struct slcompress *comp;
 #endif
@@ -612,7 +611,7 @@ sl_get_stats(struct net_device *dev)
 
 static int sl_init(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        /*
         *      Finish setting up the DEVICE info. 
@@ -630,7 +629,7 @@ static int sl_init(struct net_device *dev)
 
 static void sl_uninit(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        sl_free_bufs(sl);
 }
@@ -719,7 +718,7 @@ static void sl_sync(void)
                if ((dev = slip_devs[i]) == NULL)
                        break;
 
-               sl = dev->priv;
+               sl = netdev_priv(dev);
                if (sl->tty || sl->leased)
                        continue;
                if (dev->flags&IFF_UP)
@@ -746,7 +745,7 @@ sl_alloc(dev_t line)
                if (dev == NULL)
                        break;
 
-               sl = dev->priv;
+               sl = netdev_priv(dev);
                if (sl->leased) {
                        if (sl->line != line)
                                continue;
@@ -788,7 +787,7 @@ sl_alloc(dev_t line)
                i = sel;
                dev = slip_devs[i];
                if (score > 1) {
-                       sl = dev->priv;
+                       sl = netdev_priv(dev);
                        sl->flags &= (1 << SLF_INUSE);
                        return sl;
                }
@@ -799,7 +798,7 @@ sl_alloc(dev_t line)
                return NULL;
 
        if (dev) {
-               sl = dev->priv;
+               sl = netdev_priv(dev);
                if (test_bit(SLF_INUSE, &sl->flags)) {
                        unregister_netdevice(dev);
                        dev = NULL;
@@ -817,7 +816,7 @@ sl_alloc(dev_t line)
                dev->base_addr  = i;
        }
 
-       sl = dev->priv;
+       sl = netdev_priv(dev);
 
        /* Initialize channel control data */
        sl->magic       = SLIP_MAGIC;
@@ -1260,7 +1259,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
 
 static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
        unsigned long *p = (unsigned long *)&rq->ifr_ifru;
 
        if (sl == NULL)         /* Allocation failed ?? */
@@ -1406,7 +1405,7 @@ static void __exit slip_exit(void)
                        dev = slip_devs[i];
                        if (!dev)
                                continue;
-                       sl = dev->priv;
+                       sl = netdev_priv(dev);
                        spin_lock_bh(&sl->lock);
                        if (sl->tty) {
                                busy++;
@@ -1423,7 +1422,7 @@ static void __exit slip_exit(void)
                        continue;
                slip_devs[i] = NULL;
 
-               sl = dev->priv;
+               sl = netdev_priv(dev);
                if (sl->tty) {
                        printk(KERN_ERR "%s: tty discipline still running\n",
                               dev->name);
@@ -1475,7 +1474,7 @@ static void sl_outfill(unsigned long sls)
                        if (!netif_queue_stopped(sl->dev))
                        {
                                /* if device busy no outfill */
-                               sl->tty->driver->write(sl->tty, 0, &s, 1);
+                               sl->tty->driver->write(sl->tty, &s, 1);
                        }
                }
                else
index 5d224b6..9b75be8 100644 (file)
  *                                  smc_phy_configure
  *                                - clean up (and fix stack overrun) in PHY
  *                                  MII read/write functions
- *   09/15/04  Hayato Fujiwara    - Add m32r support.
- *                                - Modify for SMP kernel; Change spin-locked
- *                                  regions.
+ *   22/09/04  Nicolas Pitre      big update (see commit log for details)
  */
 static const char version[] =
-       "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n";
+       "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@cam.org>\n";
 
 /* Debugging level */
 #ifndef SMC_DEBUG
@@ -75,7 +73,7 @@ static const char version[] =
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/timer.h>
+#include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/crc32.h>
@@ -83,6 +81,7 @@ static const char version[] =
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/workqueue.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -177,7 +176,8 @@ struct smc_local {
         * packet, I will store the skbuff here, until I get the
         * desired memory.  Then, I'll send it out and free it.
         */
-       struct sk_buff *saved_skb;
+       struct sk_buff *pending_tx_skb;
+       struct tasklet_struct tx_task;
 
        /*
         * these are things that the kernel wants me to keep, so users
@@ -203,6 +203,11 @@ struct smc_local {
        u32     msg_enable;
        u32     phy_type;
        struct mii_if_info mii;
+
+       /* work queue */
+       struct work_struct phy_configure;
+       int     work_pending;
+
        spinlock_t lock;
 
 #ifdef SMC_USE_PXA_DMA
@@ -215,7 +220,7 @@ struct smc_local {
 #define DBG(n, args...)                                        \
        do {                                            \
                if (SMC_DEBUG >= (n))                   \
-                       printk(KERN_DEBUG args);        \
+                       printk(args);   \
        } while (0)
 
 #define PRINTK(args...)   printk(args)
@@ -260,17 +265,21 @@ static void PRINT_PKT(u_char *buf, int length)
 /* this enables an interrupt in the interrupt mask register */
 #define SMC_ENABLE_INT(x) do {                                         \
        unsigned char mask;                                             \
+       spin_lock_irq(&lp->lock);                                       \
        mask = SMC_GET_INT_MASK();                                      \
        mask |= (x);                                                    \
        SMC_SET_INT_MASK(mask);                                         \
+       spin_unlock_irq(&lp->lock);                                     \
 } while (0)
 
 /* this disables an interrupt from the interrupt mask register */
 #define SMC_DISABLE_INT(x) do {                                                \
        unsigned char mask;                                             \
+       spin_lock_irq(&lp->lock);                                       \
        mask = SMC_GET_INT_MASK();                                      \
        mask &= ~(x);                                                   \
        SMC_SET_INT_MASK(mask);                                         \
+       spin_unlock_irq(&lp->lock);                                     \
 } while (0)
 
 /*
@@ -299,10 +308,17 @@ static void PRINT_PKT(u_char *buf, int length)
 static void smc_reset(struct net_device *dev)
 {
        unsigned long ioaddr = dev->base_addr;
+       struct smc_local *lp = netdev_priv(dev);
        unsigned int ctl, cfg;
 
        DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
 
+       /* Disable all interrupts */
+       spin_lock(&lp->lock);
+       SMC_SELECT_BANK(2);
+       SMC_SET_INT_MASK(0);
+       spin_unlock(&lp->lock);
+
        /*
         * This resets the registers mostly to defaults, but doesn't
         * affect EEPROM.  That seems unnecessary
@@ -358,20 +374,24 @@ static void smc_reset(struct net_device *dev)
         * transmitted packets, to make the best use out of our limited
         * memory
         */
-#if ! THROTTLE_TX_PKTS
-       ctl |= CTL_AUTO_RELEASE;
-#else
-       ctl &= ~CTL_AUTO_RELEASE;
-#endif
+       if(!THROTTLE_TX_PKTS)
+               ctl |= CTL_AUTO_RELEASE;
+       else
+               ctl &= ~CTL_AUTO_RELEASE;
        SMC_SET_CTL(ctl);
 
-       /* Disable all interrupts */
-       SMC_SELECT_BANK(2);
-       SMC_SET_INT_MASK(0);
-
        /* Reset the MMU */
+       SMC_SELECT_BANK(2);
        SMC_SET_MMU_CMD(MC_RESET);
        SMC_WAIT_MMU_BUSY();
+
+       /* clear anything saved */
+       if (lp->pending_tx_skb != NULL) {
+               dev_kfree_skb (lp->pending_tx_skb);
+               lp->pending_tx_skb = NULL;
+               lp->stats.tx_errors++;
+               lp->stats.tx_aborted_errors++;
+       }
 }
 
 /*
@@ -390,24 +410,39 @@ static void smc_enable(struct net_device *dev)
        SMC_SET_TCR(lp->tcr_cur_mode);
        SMC_SET_RCR(lp->rcr_cur_mode);
 
+       SMC_SELECT_BANK(1);
+       SMC_SET_MAC_ADDR(dev->dev_addr);
+
        /* now, enable interrupts */
        mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT;
        if (lp->version >= (CHIP_91100 << 4))
                mask |= IM_MDINT;
        SMC_SELECT_BANK(2);
        SMC_SET_INT_MASK(mask);
+
+       /*
+        * From this point the register bank must _NOT_ be switched away
+        * to something else than bank 2 without proper locking against
+        * races with any tasklet or interrupt handlers until smc_shutdown()
+        * or smc_reset() is called.
+        */
 }
 
 /*
  * this puts the device in an inactive state
  */
-static void smc_shutdown(unsigned long ioaddr)
+static void smc_shutdown(struct net_device *dev)
 {
+       unsigned long ioaddr = dev->base_addr;
+       struct smc_local *lp = netdev_priv(dev);
+
        DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
 
        /* no more interrupts for me */
+       spin_lock(&lp->lock);
        SMC_SELECT_BANK(2);
        SMC_SET_INT_MASK(0);
+       spin_unlock(&lp->lock);
 
        /* and tell the card to stay away from that nasty outside world */
        SMC_SELECT_BANK(0);
@@ -449,6 +484,8 @@ static inline void  smc_rcv(struct net_device *dev)
                packet_len, packet_len);
 
        if (unlikely(status & RS_ERRORS)) {
+               SMC_WAIT_MMU_BUSY();
+               SMC_SET_MMU_CMD(MC_RELEASE);
                lp->stats.rx_errors++;
                if (status & RS_ALGNERR)
                        lp->stats.rx_frame_errors++;
@@ -466,17 +503,21 @@ static inline void  smc_rcv(struct net_device *dev)
                        lp->stats.multicast++;
 
                /*
-                * Actual payload is packet_len - 4 (or 3 if odd byte).
+                * Actual payload is packet_len - 6 (or 5 if odd byte).
                 * We want skb_reserve(2) and the final ctrl word
                 * (2 bytes, possibly containing the payload odd byte).
-                * Ence packet_len - 4 + 2 + 2.
+                * Furthermore, we add 2 bytes to allow rounding up to
+                * multiple of 4 bytes on 32 bit buses.
+                * Ence packet_len - 6 + 2 + 2 + 2.
                 */
                skb = dev_alloc_skb(packet_len);
                if (unlikely(skb == NULL)) {
                        printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
                                dev->name);
+                       SMC_WAIT_MMU_BUSY();
+                       SMC_SET_MMU_CMD(MC_RELEASE);
                        lp->stats.rx_dropped++;
-                       goto done;
+                       return;
                }
 
                /* Align IP header to 32 bits */
@@ -487,14 +528,18 @@ static inline void  smc_rcv(struct net_device *dev)
                        status |= RS_ODDFRAME;
 
                /*
-                * If odd length: packet_len - 3,
-                * otherwise packet_len - 4.
+                * If odd length: packet_len - 5,
+                * otherwise packet_len - 6.
+                * With the trailing ctrl byte it's packet_len - 4.
                 */
-               data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4);
+               data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6);
                data = skb_put(skb, data_len);
-               SMC_PULL_DATA(data, packet_len - 2);
+               SMC_PULL_DATA(data, packet_len - 4);
+
+               SMC_WAIT_MMU_BUSY();
+               SMC_SET_MMU_CMD(MC_RELEASE);
 
-               PRINT_PKT(data, packet_len - 2);
+               PRINT_PKT(data, packet_len - 4);
 
                dev->last_rx = jiffies;
                skb->dev = dev;
@@ -503,34 +548,76 @@ static inline void  smc_rcv(struct net_device *dev)
                lp->stats.rx_packets++;
                lp->stats.rx_bytes += data_len;
        }
-
-done:
-       SMC_WAIT_MMU_BUSY();
-       SMC_SET_MMU_CMD(MC_RELEASE);
 }
 
+#ifdef CONFIG_SMP
+/*
+ * On SMP we have the following problem:
+ *
+ *     A = smc_hardware_send_pkt()
+ *     B = smc_hard_start_xmit()
+ *     C = smc_interrupt()
+ *
+ * A and B can never be executed simultaneously.  However, at least on UP,
+ * it is possible (and even desirable) for C to interrupt execution of
+ * A or B in order to have better RX reliability and avoid overruns.
+ * C, just like A and B, must have exclusive access to the chip and
+ * each of them must lock against any other concurrent access.
+ * Unfortunately this is not possible to have C suspend execution of A or
+ * B taking place on another CPU. On UP this is no an issue since A and B
+ * are run from softirq context and C from hard IRQ context, and there is
+ * no other CPU where concurrent access can happen.
+ * If ever there is a way to force at least B and C to always be executed
+ * on the same CPU then we could use read/write locks to protect against
+ * any other concurrent access and C would always interrupt B. But life
+ * isn't that easy in a SMP world...
+ */
+#define smc_special_trylock(lock)                                      \
+({                                                                     \
+       int __ret;                                                      \
+       local_irq_disable();                                            \
+       __ret = spin_trylock(lock);                                     \
+       if (!__ret)                                                     \
+               local_irq_enable();                                     \
+       __ret;                                                          \
+})
+#define smc_special_lock(lock)         spin_lock_irq(lock)
+#define smc_special_unlock(lock)       spin_unlock_irq(lock)
+#else
+#define smc_special_trylock(lock)      (1)
+#define smc_special_lock(lock)         do { } while (0)
+#define smc_special_unlock(lock)       do { } while (0)
+#endif
+
 /*
  * This is called to actually send a packet to the chip.
- * Returns non-zero when successful.
  */
-static void smc_hardware_send_packet(struct net_device *dev)
+static void smc_hardware_send_pkt(unsigned long data)
 {
+       struct net_device *dev = (struct net_device *)data;
        struct smc_local *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
-       struct sk_buff *skb = lp->saved_skb;
+       struct sk_buff *skb;
        unsigned int packet_no, len;
        unsigned char *buf;
 
        DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
 
+       if (!smc_special_trylock(&lp->lock)) {
+               netif_stop_queue(dev);
+               tasklet_schedule(&lp->tx_task);
+               return;
+       }
+
+       skb = lp->pending_tx_skb;
+       lp->pending_tx_skb = NULL;
        packet_no = SMC_GET_AR();
        if (unlikely(packet_no & AR_FAILED)) {
                printk("%s: Memory allocation failed.\n", dev->name);
-               lp->saved_skb = NULL;
                lp->stats.tx_errors++;
                lp->stats.tx_fifo_errors++;
-               dev_kfree_skb_any(skb);
-               return;
+               smc_special_unlock(&lp->lock);
+               goto done;
        }
 
        /* point to the beginning of the packet */
@@ -555,15 +642,33 @@ static void smc_hardware_send_packet(struct net_device *dev)
        /* Send final ctl word with the last byte if there is one */
        SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG);
 
-       /* and let the chipset deal with it */
+       /*
+        * If THROTTLE_TX_PKTS is set, we look at the TX_EMPTY flag
+        * before queueing this packet for TX, and if it's clear then
+        * we stop the queue here.  This will have the effect of
+        * having at most 2 packets queued for TX in the chip's memory
+        * at all time. If THROTTLE_TX_PKTS is not set then the queue
+        * is stopped only when memory allocation (MC_ALLOC) does not
+        * succeed right away.
+        */
+       if (THROTTLE_TX_PKTS && !(SMC_GET_INT() & IM_TX_EMPTY_INT))
+               netif_stop_queue(dev);
+
+       /* queue the packet for TX */
        SMC_SET_MMU_CMD(MC_ENQUEUE);
        SMC_ACK_INT(IM_TX_EMPTY_INT);
+       smc_special_unlock(&lp->lock);
 
        dev->trans_start = jiffies;
-       dev_kfree_skb_any(skb);
-       lp->saved_skb = NULL;
        lp->stats.tx_packets++;
        lp->stats.tx_bytes += len;
+
+       SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT);
+
+done:  if (!THROTTLE_TX_PKTS)
+               netif_wake_queue(dev);
+
+       dev_kfree_skb(skb);
 }
 
 /*
@@ -576,15 +681,12 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct smc_local *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
-       unsigned int numPages, poll_count, status, saved_bank;
-       unsigned long flags;
+       unsigned int numPages, poll_count, status;
 
        DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
 
-       spin_lock_irqsave(&lp->lock, flags);
-
-       BUG_ON(lp->saved_skb != NULL);
-       lp->saved_skb = skb;
+       BUG_ON(lp->pending_tx_skb != NULL);
+       lp->pending_tx_skb = skb;
 
        /*
         * The MMU wants the number of pages to be the number of 256 bytes
@@ -600,17 +702,16 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
        if (unlikely(numPages > 7)) {
                printk("%s: Far too big packet error.\n", dev->name);
-               lp->saved_skb = NULL;
+               lp->pending_tx_skb = NULL;
                lp->stats.tx_errors++;
                lp->stats.tx_dropped++;
                dev_kfree_skb(skb);
-               spin_unlock_irqrestore(&lp->lock, flags);
                return 0;
        }
 
+       smc_special_lock(&lp->lock);
+
        /* now, try to allocate the memory */
-       saved_bank = SMC_CURRENT_BANK();
-       SMC_SELECT_BANK(2);
        SMC_SET_MMU_CMD(MC_ALLOC | numPages);
 
        /*
@@ -626,6 +727,8 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        } while (--poll_count);
 
+       smc_special_unlock(&lp->lock);
+
        if (!poll_count) {
                /* oh well, wait until the chip finds memory later */
                netif_stop_queue(dev);
@@ -635,25 +738,10 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                /*
                 * Allocation succeeded: push packet to the chip's own memory
                 * immediately.
-                *
-                * If THROTTLE_TX_PKTS is selected that means we don't want
-                * more than a single TX packet taking up space in the chip's
-                * internal memory at all time, in which case we stop the
-                * queue right here until we're notified of TX completion.
-                *
-                * Otherwise we're quite happy to feed more TX packets right
-                * away for better TX throughput, in which case the queue is
-                * left active.
                 */  
-#if THROTTLE_TX_PKTS
-               netif_stop_queue(dev);
-#endif
-               smc_hardware_send_packet(dev);
-               SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT);
+               smc_hardware_send_pkt((unsigned long)dev);
        }
 
-       SMC_SELECT_BANK(saved_bank);
-       spin_unlock_irqrestore(&lp->lock, flags);
        return 0;
 }
 
@@ -767,10 +855,8 @@ static unsigned int smc_mii_in(struct net_device *dev, int bits)
 static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg)
 {
        unsigned long ioaddr = dev->base_addr;
-       unsigned int phydata, old_bank;
+       unsigned int phydata;
 
-       /* Save the current bank, and select bank 3 */
-       old_bank = SMC_CURRENT_BANK();
        SMC_SELECT_BANK(3);
 
        /* Idle - 32 ones */
@@ -785,12 +871,10 @@ static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg)
        /* Return to idle state */
        SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO));
 
-       /* And select original bank */
-       SMC_SELECT_BANK(old_bank);
-
        DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
                __FUNCTION__, phyaddr, phyreg, phydata);
 
+       SMC_SELECT_BANK(2);
        return phydata;
 }
 
@@ -801,10 +885,7 @@ static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg,
                          int phydata)
 {
        unsigned long ioaddr = dev->base_addr;
-       unsigned int old_bank;
 
-       /* Save the current bank, and select bank 3 */
-       old_bank = SMC_CURRENT_BANK();
        SMC_SELECT_BANK(3);
 
        /* Idle - 32 ones */
@@ -816,17 +897,16 @@ static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg,
        /* Return to idle state */
        SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO));
 
-       /* And select original bank */
-       SMC_SELECT_BANK(old_bank);
-
        DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
                __FUNCTION__, phyaddr, phyreg, phydata);
+
+       SMC_SELECT_BANK(2);
 }
 
 /*
  * Finds and reports the PHY address
  */
-static void smc_detect_phy(struct net_device *dev)
+static void smc_phy_detect(struct net_device *dev)
 {
        struct smc_local *lp = netdev_priv(dev);
        int phyaddr;
@@ -893,7 +973,9 @@ static int smc_phy_fixed(struct net_device *dev)
        smc_phy_write(dev, phyaddr, MII_BMCR, bmcr);
 
        /* Re-Configure the Receive/Phy Control register */
+       SMC_SELECT_BANK(0);
        SMC_SET_RPC(lp->rpc_cur_mode);
+       SMC_SELECT_BANK(2);
 
        return 1;
 }
@@ -941,13 +1023,10 @@ static int smc_phy_reset(struct net_device *dev, int phy)
  */
 static void smc_phy_powerdown(struct net_device *dev, int phy)
 {
-       struct smc_local *lp = netdev_priv(dev);
        unsigned int bmcr;
 
-       spin_lock_irq(&lp->lock);
        bmcr = smc_phy_read(dev, phy, MII_BMCR);
        smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
-       spin_unlock_irq(&lp->lock);
 }
 
 /*
@@ -964,8 +1043,6 @@ static void smc_phy_check_media(struct net_device *dev, int init)
        unsigned long ioaddr = dev->base_addr;
 
        if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
-               unsigned int old_bank;
-
                /* duplex state has changed */
                if (lp->mii.full_duplex) {
                        lp->tcr_cur_mode |= TCR_SWFDUP;
@@ -973,10 +1050,8 @@ static void smc_phy_check_media(struct net_device *dev, int init)
                        lp->tcr_cur_mode &= ~TCR_SWFDUP;
                }
 
-               old_bank = SMC_CURRENT_BANK();
                SMC_SELECT_BANK(0);
                SMC_SET_TCR(lp->tcr_cur_mode);
-               SMC_SELECT_BANK(old_bank);
        }
 }
 
@@ -989,8 +1064,9 @@ static void smc_phy_check_media(struct net_device *dev, int init)
  * of autonegotiation.)  If the RPC ANEG bit is cleared, the selection
  * is controlled by the RPC SPEED and RPC DPLX bits.
  */
-static void smc_phy_configure(struct net_device *dev)
+static void smc_phy_configure(void *data)
 {
+       struct net_device *dev = data;
        struct smc_local *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
        int phyaddr = lp->mii.phy_id;
@@ -1082,6 +1158,7 @@ static void smc_phy_configure(struct net_device *dev)
 
 smc_phy_configure_exit:
        spin_unlock_irq(&lp->lock);
+       lp->work_pending = 0;
 }
 
 /*
@@ -1117,12 +1194,13 @@ static void smc_10bt_check_media(struct net_device *dev, int init)
 {
        struct smc_local *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
-       unsigned int old_carrier, new_carrier, old_bank;
+       unsigned int old_carrier, new_carrier;
 
-       old_bank = SMC_CURRENT_BANK();
-       SMC_SELECT_BANK(0);
        old_carrier = netif_carrier_ok(dev) ? 1 : 0;
+
+       SMC_SELECT_BANK(0);
        new_carrier = SMC_inw(ioaddr, EPH_STATUS_REG) & ES_LINK_OK ? 1 : 0;
+       SMC_SELECT_BANK(2);
 
        if (init || (old_carrier != new_carrier)) {
                if (!new_carrier) {
@@ -1134,24 +1212,20 @@ static void smc_10bt_check_media(struct net_device *dev, int init)
                        printk(KERN_INFO "%s: link %s\n", dev->name,
                               new_carrier ? "up" : "down");
        }
-       SMC_SELECT_BANK(old_bank);
 }
 
 static void smc_eph_interrupt(struct net_device *dev)
 {
        unsigned long ioaddr = dev->base_addr;
-       unsigned int old_bank, ctl;
+       unsigned int ctl;
 
        smc_10bt_check_media(dev, 0);
 
-       old_bank = SMC_CURRENT_BANK();
        SMC_SELECT_BANK(1);
-
        ctl = SMC_GET_CTL();
        SMC_SET_CTL(ctl & ~CTL_LE_ENABLE);
        SMC_SET_CTL(ctl);
-
-       SMC_SELECT_BANK(old_bank);
+       SMC_SELECT_BANK(2);
 }
 
 /*
@@ -1164,14 +1238,17 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        unsigned long ioaddr = dev->base_addr;
        struct smc_local *lp = netdev_priv(dev);
        int status, mask, timeout, card_stats;
-       int saved_bank, saved_pointer;
+       int saved_pointer;
 
        DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
 
        spin_lock(&lp->lock);
 
-       saved_bank = SMC_CURRENT_BANK();
-       SMC_SELECT_BANK(2);
+       /* A preamble may be used when there is a potential race
+        * between the interruptible transmit functions and this
+        * ISR. */
+       SMC_INTERRUPT_PREAMBLE;
+
        saved_pointer = SMC_GET_PTR();
        mask = SMC_GET_INT_MASK();
        SMC_SET_INT_MASK(0);
@@ -1182,7 +1259,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        do {
                status = SMC_GET_INT();
 
-               DBG(2, "%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",
+               DBG(2, "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",
                        dev->name, status, mask,
                        ({ int meminfo; SMC_SELECT_BANK(0);
                           meminfo = SMC_GET_MIR();
@@ -1200,17 +1277,12 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        DBG(3, "%s: TX int\n", dev->name);
                        smc_tx(dev);
                        SMC_ACK_INT(IM_TX_INT);
-#if THROTTLE_TX_PKTS
-                       netif_wake_queue(dev);
-#endif
+                       if (THROTTLE_TX_PKTS)
+                               netif_wake_queue(dev);
                } else if (status & IM_ALLOC_INT) {
                        DBG(3, "%s: Allocation irq\n", dev->name);
-                       smc_hardware_send_packet(dev);
-                       mask |= (IM_TX_INT | IM_TX_EMPTY_INT);
+                       tasklet_hi_schedule(&lp->tx_task);
                        mask &= ~IM_ALLOC_INT;
-#if ! THROTTLE_TX_PKTS
-                       netif_wake_queue(dev);
-#endif
                } else if (status & IM_TX_EMPTY_INT) {
                        DBG(3, "%s: TX empty\n", dev->name);
                        mask &= ~IM_TX_EMPTY_INT;
@@ -1240,17 +1312,16 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        SMC_ACK_INT(IM_ERCV_INT);
                        PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name);
                }
-
        } while (--timeout);
 
        /* restore register states */
-       SMC_SET_INT_MASK(mask);
        SMC_SET_PTR(saved_pointer);
-       SMC_SELECT_BANK(saved_bank);
+       SMC_SET_INT_MASK(mask);
+
+       spin_unlock(&lp->lock);
 
        DBG(3, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout);
 
-       spin_unlock(&lp->lock);
        /*
         * We return IRQ_HANDLED unconditionally here even if there was
         * nothing to do.  There is a possibility that a packet might
@@ -1266,100 +1337,41 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 static void smc_timeout(struct net_device *dev)
 {
        struct smc_local *lp = netdev_priv(dev);
-       unsigned long flags;
+       unsigned long ioaddr = dev->base_addr;
+       int status, mask, meminfo, fifo;
 
-       spin_lock_irqsave(&lp->lock, flags);
        DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
 
+       spin_lock_irq(&lp->lock);
+       status = SMC_GET_INT();
+       mask = SMC_GET_INT_MASK();
+       fifo = SMC_GET_FIFO();
+       SMC_SELECT_BANK(0);
+       meminfo = SMC_GET_MIR();
+       SMC_SELECT_BANK(2);
+       spin_unlock_irq(&lp->lock);
+       PRINTK( "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",
+               dev->name, status, mask, meminfo, fifo );
+
        smc_reset(dev);
        smc_enable(dev);
 
-#if 0
        /*
         * Reconfiguring the PHY doesn't seem like a bad idea here, but
-        * it introduced a problem.  Now that this is a timeout routine,
-        * we are getting called from within an interrupt context.
-        * smc_phy_configure() calls msleep() which calls
-        * schedule_timeout() which calls schedule().  When schedule()
-        * is called from an interrupt context, it prints out
-        * "Scheduling in interrupt" and then calls BUG().  This is
-        * obviously not desirable.  This was worked around by removing
-        * the call to smc_phy_configure() here because it didn't seem
-        * absolutely necessary.  Ultimately, if msleep() is
-        * supposed to be usable from an interrupt context (which it
-        * looks like it thinks it should handle), it should be fixed.
+        * smc_phy_configure() calls msleep() which calls schedule_timeout()
+        * which calls schedule().  Hence we use a work queue.
         */
-       if (lp->phy_type != 0)
-               smc_phy_configure(dev);
-#endif
-
-       /* clear anything saved */
-       if (lp->saved_skb != NULL) {
-               dev_kfree_skb (lp->saved_skb);
-               lp->saved_skb = NULL;
-               lp->stats.tx_errors++;
-               lp->stats.tx_aborted_errors++;
+       if (lp->phy_type != 0) {
+               if (schedule_work(&lp->phy_configure)) {
+                       lp->work_pending = 1;
+               }
        }
+
        /* We can accept TX packets again */
        dev->trans_start = jiffies;
-
-       spin_unlock_irqrestore(&lp->lock, flags);
-
        netif_wake_queue(dev);
 }
 
-/*
- *    This sets the internal hardware table to filter out unwanted multicast
- *    packets before they take up memory.
- *
- *    The SMC chip uses a hash table where the high 6 bits of the CRC of
- *    address are the offset into the table.  If that bit is 1, then the
- *    multicast packet is accepted.  Otherwise, it's dropped silently.
- *
- *    To use the 6 bits as an offset into the table, the high 3 bits are the
- *    number of the 8 bit register, while the low 3 bits are the bit within
- *    that register.
- *
- *    This routine is based very heavily on the one provided by Peter Cammaert.
- */
-static void
-smc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs)
-{
-       int i;
-       unsigned char multicast_table[8];
-       struct dev_mc_list *cur_addr;
-
-       /* table for flipping the order of 3 bits */
-       static unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
-
-       /* start with a table of all zeros: reject all */
-       memset(multicast_table, 0, sizeof(multicast_table));
-
-       cur_addr = addrs;
-       for (i = 0; i < count; i++, cur_addr = cur_addr->next) {
-               int position;
-
-               /* do we have a pointer here? */
-               if (!cur_addr)
-                       break;
-               /* make sure this is a multicast address - shouldn't this
-                  be a given if we have it here ? */
-               if (!(*cur_addr->dmi_addr & 1))
-                       continue;
-
-               /* only use the low order bits */
-               position = crc32_le(~0, cur_addr->dmi_addr, 6) & 0x3f;
-
-               /* do some messy swapping to put the bit in the right spot */
-               multicast_table[invert3[position&7]] |=
-                                       (1<<invert3[(position>>3)&7]);
-
-       }
-       /* now, the table can be loaded into the chipset */
-       SMC_SELECT_BANK(3);
-       SMC_SET_MCAST(multicast_table);
-}
-
 /*
  * This routine will, depending on the values passed to it,
  * either make it accept multicast packets, go into
@@ -1370,14 +1382,14 @@ static void smc_set_multicast_list(struct net_device *dev)
 {
        struct smc_local *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
+       unsigned char multicast_table[8];
+       int update_multicast = 0;
 
        DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
 
-       SMC_SELECT_BANK(0);
        if (dev->flags & IFF_PROMISC) {
                DBG(2, "%s: RCR_PRMS\n", dev->name);
                lp->rcr_cur_mode |= RCR_PRMS;
-               SMC_SET_RCR(lp->rcr_cur_mode);
        }
 
 /* BUG?  I never disable promiscuous mode if multicasting was turned on.
@@ -1391,38 +1403,78 @@ static void smc_set_multicast_list(struct net_device *dev)
         * checked before the table is
         */
        else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) {
-               lp->rcr_cur_mode |= RCR_ALMUL;
-               SMC_SET_RCR(lp->rcr_cur_mode);
                DBG(2, "%s: RCR_ALMUL\n", dev->name);
+               lp->rcr_cur_mode |= RCR_ALMUL;
        }
 
        /*
-        * We just get all multicast packets even if we only want them
-        * from one source.  This will be changed at some future point.
+        * This sets the internal hardware table to filter out unwanted
+        * multicast packets before they take up memory.
+        *
+        * The SMC chip uses a hash table where the high 6 bits of the CRC of
+        * address are the offset into the table.  If that bit is 1, then the
+        * multicast packet is accepted.  Otherwise, it's dropped silently.
+        *
+        * To use the 6 bits as an offset into the table, the high 3 bits are
+        * the number of the 8 bit register, while the low 3 bits are the bit
+        * within that register.
         */
        else if (dev->mc_count)  {
-               /* support hardware multicasting */
+               int i;
+               struct dev_mc_list *cur_addr;
+
+               /* table for flipping the order of 3 bits */
+               static const unsigned char invert3[] = {0, 4, 2, 6, 1, 5, 3, 7};
+
+               /* start with a table of all zeros: reject all */
+               memset(multicast_table, 0, sizeof(multicast_table));
+
+               cur_addr = dev->mc_list;
+               for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) {
+                       int position;
+
+                       /* do we have a pointer here? */
+                       if (!cur_addr)
+                               break;
+                       /* make sure this is a multicast address -
+                          shouldn't this be a given if we have it here ? */
+                       if (!(*cur_addr->dmi_addr & 1))
+                               continue;
+
+                       /* only use the low order bits */
+                       position = crc32_le(~0, cur_addr->dmi_addr, 6) & 0x3f;
+
+                       /* do some messy swapping to put the bit in the right spot */
+                       multicast_table[invert3[position&7]] |=
+                               (1<<invert3[(position>>3)&7]);
+               }
 
                /* be sure I get rid of flags I might have set */
                lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
-               SMC_SET_RCR(lp->rcr_cur_mode);
-               /*
-                * NOTE: this has to set the bank, so make sure it is the
-                * last thing called.  The bank is set to zero at the top
-                */
-               smc_setmulticast(ioaddr, dev->mc_count, dev->mc_list);
+
+               /* now, the table can be loaded into the chipset */
+               update_multicast = 1;
        } else  {
                DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name);
                lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
-               SMC_SET_RCR(lp->rcr_cur_mode);
 
                /*
                 * since I'm disabling all multicast entirely, I need to
                 * clear the multicast list
                 */
+               memset(multicast_table, 0, sizeof(multicast_table));
+               update_multicast = 1;
+       }
+
+       spin_lock_irq(&lp->lock);
+       SMC_SELECT_BANK(0);
+       SMC_SET_RCR(lp->rcr_cur_mode);
+       if (update_multicast) {
                SMC_SELECT_BANK(3);
-               SMC_CLEAR_MCAST();
+               SMC_SET_MCAST(multicast_table);
        }
+       SMC_SELECT_BANK(2);
+       spin_unlock_irq(&lp->lock);
 }
 
 
@@ -1435,7 +1487,6 @@ static int
 smc_open(struct net_device *dev)
 {
        struct smc_local *lp = netdev_priv(dev);
-       unsigned long ioaddr = dev->base_addr;
 
        DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
 
@@ -1445,13 +1496,10 @@ smc_open(struct net_device *dev)
         * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
         */
        if (!is_valid_ether_addr(dev->dev_addr)) {
-               DBG(2, "smc_open: no valid ethernet hw addr\n");
+               PRINTK("%s: no valid ethernet hw addr\n", __FUNCTION__);
                return -EINVAL;
        }
 
-       /* clear out all the junk that was put here before... */
-       lp->saved_skb = NULL;
-
        /* Setup the default Register Modes */
        lp->tcr_cur_mode = TCR_DEFAULT;
        lp->rcr_cur_mode = RCR_DEFAULT;
@@ -1468,10 +1516,7 @@ smc_open(struct net_device *dev)
        smc_reset(dev);
        smc_enable(dev);
 
-       SMC_SELECT_BANK(1);
-       SMC_SET_MAC_ADDR(dev->dev_addr);
-
-       /* Configure the PHY */
+       /* Configure the PHY, initialize the link state */
        if (lp->phy_type != 0)
                smc_phy_configure(dev);
        else {
@@ -1480,12 +1525,6 @@ smc_open(struct net_device *dev)
                spin_unlock_irq(&lp->lock);
        }
 
-       /*
-        * make sure to initialize the link state with netif_carrier_off()
-        * somewhere, too --jgarzik
-        *
-        * smc_phy_configure() and smc_10bt_check_media() does that. --rmk
-        */
        netif_start_queue(dev);
        return 0;
 }
@@ -1507,10 +1546,28 @@ static int smc_close(struct net_device *dev)
        netif_carrier_off(dev);
 
        /* clear everything */
-       smc_shutdown(dev->base_addr);
+       smc_shutdown(dev);
 
-       if (lp->phy_type != 0)
+       if (lp->phy_type != 0) {
+               /* We need to ensure that no calls to
+                  smc_phy_configure are pending.
+
+                  flush_scheduled_work() cannot be called because we
+                  are running with the netlink semaphore held (from
+                  devinet_ioctl()) and the pending work queue
+                  contains linkwatch_event() (scheduled by
+                  netif_carrier_off() above). linkwatch_event() also
+                  wants the netlink semaphore.
+               */
+               while(lp->work_pending)
+                       schedule();
                smc_phy_powerdown(dev, lp->mii.phy_id);
+       }
+
+       if (lp->pending_tx_skb) {
+               dev_kfree_skb(lp->pending_tx_skb);
+               lp->pending_tx_skb = NULL;
+       }
 
        return 0;
 }
@@ -1800,6 +1857,7 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr)
        /* fill in some of the fields */
        dev->base_addr = ioaddr;
        lp->version = revision_register & 0xff;
+       spin_lock_init(&lp->lock);
 
        /* Get the MAC address */
        SMC_SELECT_BANK(1);
@@ -1855,7 +1913,8 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr)
        dev->set_multicast_list = smc_set_multicast_list;
        dev->ethtool_ops = &smc_ethtool_ops;
 
-       spin_lock_init(&lp->lock);
+       tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev);
+       INIT_WORK(&lp->phy_configure, smc_phy_configure, dev);
        lp->mii.phy_id_mask = 0x1f;
        lp->mii.reg_num_mask = 0x1f;
        lp->mii.force_media = 0;
@@ -1868,7 +1927,7 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr)
         * Locate the phy, if any.
         */
        if (lp->version >= (CHIP_91100 << 4))
-               smc_detect_phy(dev);
+               smc_phy_detect(dev);
 
        /* Set default parameters */
        lp->msg_enable = NETIF_MSG_LINK;
@@ -1885,9 +1944,8 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr)
        if (retval)
                goto err_out;
 
-#if !defined(__m32r__)
        set_irq_type(dev->irq, IRQT_RISING);
-#endif
+
 #ifdef SMC_USE_PXA_DMA
        {
                int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW,
@@ -2121,7 +2179,7 @@ static int smc_drv_suspend(struct device *dev, u32 state, u32 level)
        if (ndev && level == SUSPEND_DISABLE) {
                if (netif_running(ndev)) {
                        netif_device_detach(ndev);
-                       smc_shutdown(ndev->base_addr);
+                       smc_shutdown(ndev);
                }
        }
        return 0;
@@ -2134,15 +2192,12 @@ static int smc_drv_resume(struct device *dev, u32 level)
 
        if (ndev && level == RESUME_ENABLE) {
                struct smc_local *lp = netdev_priv(ndev);
-               unsigned long ioaddr = ndev->base_addr;
 
                if (pdev->num_resources == 3)
                        smc_enable_device(pdev->resource[2].start);
                if (netif_running(ndev)) {
                        smc_reset(ndev);
                        smc_enable(ndev);
-                       SMC_SELECT_BANK(1);
-                       SMC_SET_MAC_ADDR(ndev->dev_addr);
                        if (lp->phy_type != 0)
                                smc_phy_configure(ndev);
                        netif_device_attach(ndev);
index cf74b74..fad8c04 100644 (file)
  * Define your architecture specific bus configuration parameters here.
  */
 
-#if    defined(CONFIG_SA1100_GRAPHICSCLIENT) || \
-       defined(CONFIG_SA1100_PFS168) || \
-       defined(CONFIG_SA1100_FLEXANET) || \
-       defined(CONFIG_SA1100_GRAPHICSMASTER) || \
-       defined(CONFIG_ARCH_LUBBOCK)
+#if    defined(CONFIG_ARCH_LUBBOCK)
 
 /* We can only do 16-bit reads and writes in the static memory space. */
 #define SMC_CAN_USE_8BIT       0
        } while (0)
 #define set_irq_type(irq, type)
 
+#elif defined(CONFIG_SA1100_PLEB)
+/* We can only do 16-bit reads and writes in the static memory space. */
+#define SMC_CAN_USE_8BIT       1
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      0
+#define SMC_IO_SHIFT           0
+#define SMC_NOWAIT             1
+
+#define SMC_inb(a, r)          inb((a) + (r))
+#define SMC_insb(a, r, p, l)   insb((a) + (r), p, (l))
+#define SMC_inw(a, r)          inw((a) + (r))
+#define SMC_insw(a, r, p, l)   insw((a) + (r), p, l)
+#define SMC_outb(v, a, r)      outb(v, (a) + (r))
+#define SMC_outsb(a, r, p, l)  outsb((a) + (r), p, (l))
+#define SMC_outw(v, a, r)      outw(v, (a) + (r))
+#define SMC_outsw(a, r, p, l)  outsw((a) + (r), p, l)
+
+#define set_irq_type(irq, type) do {} while (0)
+
 #elif defined(CONFIG_SA1100_ASSABET)
 
 #include <asm/arch/neponset.h>
@@ -173,6 +188,58 @@ SMC_outw(u16 val, unsigned long ioaddr, int reg)
 #define SMC_insw(a, r, p, l)   insw((a) + (r) - 0xa0000000, p, l)
 #define SMC_outsw(a, r, p, l)  outsw((a) + (r) - 0xa0000000, p, l)
 
+#define set_irq_type(irq, type)        do {} while(0)
+
+#define RPC_LSA_DEFAULT                RPC_LED_TX_RX
+#define RPC_LSB_DEFAULT                RPC_LED_100_10
+
+#elif  defined(CONFIG_MACH_LPD7A400) || defined(CONFIG_MACH_LPD7A404)
+
+/* The LPD7A40X_IOBARRIER is necessary to overcome a mismatch between
+ * the way that the CPU handles chip selects and the way that the SMC
+ * chip expects the chip select to operate.  Refer to
+ * Documentation/arm/Sharp-LH/IOBarrier for details.  The read from
+ * IOBARRIER is a byte as a least-common denominator of possible
+ * regions to use as the barrier.  It would be wasteful to read 32
+ * bits from a byte oriented region.
+ *
+ * There is no explicit protection against interrupts intervening
+ * between the writew and the IOBARRIER.  In SMC ISR there is a
+ * preamble that performs an IOBARRIER in the extremely unlikely event
+ * that the driver interrupts itself between a writew to the chip an
+ * the IOBARRIER that follows *and* the cache is large enough that the
+ * first off-chip access while handing the interrupt is to the SMC
+ * chip.  Other devices in the same address space as the SMC chip must
+ * be aware of the potential for trouble and perform a similar
+ * IOBARRIER on entry to their ISR.
+ */
+
+#include <asm/arch/constants.h>        /* IOBARRIER_VIRT */
+
+#define SMC_CAN_USE_8BIT       0
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      0
+#define SMC_NOWAIT             0
+#define LPD7A40X_IOBARRIER     readb (IOBARRIER_VIRT)
+
+#define SMC_inw(a,r)           readw ((void*) ((a) + (r)))
+#define SMC_insw(a,r,p,l)      readsw ((void*) ((a) + (r)), p, l)
+#define SMC_outw(v,a,r)             ({ writew ((v), (a) + (r)); LPD7A40X_IOBARRIER; })
+
+static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l)
+{
+       unsigned short* ps = (unsigned short*) p;
+       while (l-- > 0) {
+               writew (*ps++, a + r);
+               LPD7A40X_IOBARRIER;
+       }
+}
+
+#define SMC_INTERRUPT_PREAMBLE LPD7A40X_IOBARRIER
+
+#define RPC_LSA_DEFAULT                RPC_LED_TX_RX
+#define RPC_LSB_DEFAULT                RPC_LED_100_10
+
 #else
 
 #define SMC_CAN_USE_8BIT       1
@@ -202,8 +269,9 @@ SMC_outw(u16 val, unsigned long ioaddr, int reg)
  * different and probably not worth it for that reason, and not as critical
  * as RX which can overrun memory and lose packets.
  */
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <asm/dma.h>
+#include <asm/arch/pxa-regs.h>
 
 #ifdef SMC_insl
 #undef SMC_insl
@@ -223,21 +291,23 @@ smc_pxa_dma_insl(u_long ioaddr, u_long physaddr, int reg, int dma,
 
        /* 64 bit alignment is required for memory to memory DMA */
        if ((long)buf & 4) {
-               *((u32 *)buf)++ = SMC_inl(ioaddr, reg);
+               *((u32 *)buf) = SMC_inl(ioaddr, reg);
+               buf += 4;
                len--;
        }
 
        len *= 4;
-       dmabuf = dma_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE);
+       dmabuf = dma_map_single(NULL, buf, len, DMA_FROM_DEVICE);
        DCSR(dma) = DCSR_NODESC;
        DTADR(dma) = dmabuf;
        DSADR(dma) = physaddr + reg;
        DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
                     DCMD_WIDTH4 | (DCMD_LENGTH & len));
        DCSR(dma) = DCSR_NODESC | DCSR_RUN;
-       while (!(DCSR(dma) & DCSR_STOPSTATE));
+       while (!(DCSR(dma) & DCSR_STOPSTATE))
+               cpu_relax();
        DCSR(dma) = 0;
-       dma_unmap_single(NULL, dmabuf, len, PCI_DMA_FROMDEVICE);
+       dma_unmap_single(NULL, dmabuf, len, DMA_FROM_DEVICE);
 }
 #endif
 
@@ -259,21 +329,23 @@ smc_pxa_dma_insw(u_long ioaddr, u_long physaddr, int reg, int dma,
 
        /* 64 bit alignment is required for memory to memory DMA */
        while ((long)buf & 6) {
-               *((u16 *)buf)++ = SMC_inw(ioaddr, reg);
+               *((u16 *)buf) = SMC_inw(ioaddr, reg);
+               buf += 2;
                len--;
        }
 
        len *= 2;
-       dmabuf = dma_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE);
+       dmabuf = dma_map_single(NULL, buf, len, DMA_FROM_DEVICE);
        DCSR(dma) = DCSR_NODESC;
        DTADR(dma) = dmabuf;
        DSADR(dma) = physaddr + reg;
        DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
                     DCMD_WIDTH2 | (DCMD_LENGTH & len));
        DCSR(dma) = DCSR_NODESC | DCSR_RUN;
-       while (!(DCSR(dma) & DCSR_STOPSTATE));
+       while (!(DCSR(dma) & DCSR_STOPSTATE))
+               cpu_relax();
        DCSR(dma) = 0;
-       dma_unmap_single(NULL, dmabuf, len, PCI_DMA_FROMDEVICE);
+       dma_unmap_single(NULL, dmabuf, len, DMA_FROM_DEVICE);
 }
 #endif
 
@@ -762,16 +834,9 @@ static const char * chip_ids[ 16 ] =  {
                SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG );  \
        } while (0)
 
-#define SMC_CLEAR_MCAST()                                              \
-       do {                                                            \
-               SMC_outw( 0, ioaddr, MCAST_REG1 );                      \
-               SMC_outw( 0, ioaddr, MCAST_REG2 );                      \
-               SMC_outw( 0, ioaddr, MCAST_REG3 );                      \
-               SMC_outw( 0, ioaddr, MCAST_REG4 );                      \
-       } while (0)
 #define SMC_SET_MCAST(x)                                               \
        do {                                                            \
-               unsigned char *mt = (x);                                \
+               const unsigned char *mt = (x);                          \
                SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 );   \
                SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 );   \
                SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 );   \
@@ -876,5 +941,8 @@ static const char * chip_ids[ 16 ] =  {
        })
 #endif
 
+#if !defined (SMC_INTERRUPT_PREAMBLE)
+# define SMC_INTERRUPT_PREAMBLE
+#endif
 
 #endif  /* _SMC91X_H_ */
index 25d3502..025dcd8 100644 (file)
@@ -22,9 +22,9 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 
 #include <asm/auxio.h>
-#include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/dma.h>
 #include <asm/idprom.h>
index 6e4bb57..d2d3459 100644 (file)
@@ -94,9 +94,9 @@ static char lancestr[] = "LANCE";
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
index 1ed3ff5..37ef1b8 100644 (file)
@@ -27,9 +27,9 @@ static char version[] =
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
index a50df64..47d7d6d 100644 (file)
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <linux/bitops.h>
 
 #include <net/checksum.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 
 #include "3c359.h"
 
index 471c6a8..bd4a2bc 100644 (file)
@@ -457,14 +457,7 @@ static struct pci_driver abyss_driver = {
 
 static int __init abyss_init (void)
 {
-       int rc = pci_register_driver (&abyss_driver);
-       if (rc < 0)
-               return rc;
-       if (rc == 0) {
-               pci_unregister_driver (&abyss_driver);
-               return -ENODEV;
-       }
-       return 0;
+       return pci_register_driver(&abyss_driver);
 }
 
 static void __exit abyss_rmmod (void)
index b68f195..37ddb5c 100644 (file)
@@ -243,14 +243,7 @@ static struct pci_driver tms_pci_driver = {
 
 static int __init tms_pci_init (void)
 {
-       int rc = pci_register_driver (&tms_pci_driver);
-       if (rc < 0)
-               return rc;
-       if (rc == 0) {
-               pci_unregister_driver (&tms_pci_driver);
-               return -ENODEV;
-       }
-       return 0;
+       return pci_register_driver(&tms_pci_driver);
 }
 
 static void __exit tms_pci_rmmod (void)
index 6e65890..26cc4f6 100644 (file)
@@ -28,9 +28,9 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/ethtool.h>
+#include <linux/bitops.h>
 
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 
 #ifdef DEBUG
@@ -117,6 +117,9 @@ static int xircom_open(struct net_device *dev);
 static int xircom_close(struct net_device *dev);
 static void xircom_up(struct xircom_private *card);
 static struct net_device_stats *xircom_get_stats(struct net_device *dev);
+#if CONFIG_NET_POLL_CONTROLLER
+static void xircom_poll_controller(struct net_device *dev);
+#endif
 
 static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset);
 static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset);
@@ -256,7 +259,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
        private->dev = dev;
        private->pdev = pdev;
        private->io_port = pci_resource_start(pdev, 0);
-       private->lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&private->lock);
        dev->irq = pdev->irq;
        dev->base_addr = private->io_port;
        
@@ -269,6 +272,9 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
        dev->stop = &xircom_close;
        dev->get_stats = &xircom_get_stats;
        dev->priv = private;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = &xircom_poll_controller;
+#endif
        SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
        pci_set_drvdata(pdev, dev);
 
@@ -500,6 +506,14 @@ static struct net_device_stats *xircom_get_stats(struct net_device *dev)
 } 
                                                  
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void xircom_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       xircom_interrupt(dev->irq, dev, NULL);
+       enable_irq(dev->irq);
+}
+#endif
 
 
 static void initialize_card(struct xircom_private *card)
index 57a6d29..1886fe6 100644 (file)
@@ -251,14 +251,14 @@ static int velocity_soft_reset(struct velocity_info *vptr);
 static void mii_init(struct velocity_info *vptr, u32 mii_status);
 static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
 static void velocity_print_link_status(struct velocity_info *vptr);
-static void safe_disable_mii_autopoll(struct mac_regs * regs);
+static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs);
 static void velocity_shutdown(struct velocity_info *vptr);
 static void enable_flow_control_ability(struct velocity_info *vptr);
-static void enable_mii_autopoll(struct mac_regs * regs);
-static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata);
-static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data);
-static u32 mii_check_media_mode(struct mac_regs * regs);
-static u32 check_connection_type(struct mac_regs * regs);
+static void enable_mii_autopoll(struct mac_regs __iomem * regs);
+static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 * pdata);
+static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data);
+static u32 mii_check_media_mode(struct mac_regs __iomem * regs);
+static u32 check_connection_type(struct mac_regs __iomem * regs);
 static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
 
 #ifdef CONFIG_PM
@@ -462,7 +462,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
 
 static void velocity_init_cam_filter(struct velocity_info *vptr)
 {
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
 
        /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
        WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -503,7 +503,7 @@ static void velocity_init_cam_filter(struct velocity_info *vptr)
 static void velocity_rx_reset(struct velocity_info *vptr)
 {
 
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        int i;
 
        vptr->rd_dirty = vptr->rd_filled = vptr->rd_curr = 0;
@@ -532,7 +532,7 @@ static void velocity_rx_reset(struct velocity_info *vptr)
 static void velocity_init_registers(struct velocity_info *vptr, 
                                    enum velocity_init_type type)
 {
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        int i, mii_status;
 
        mac_wol_reset(regs);
@@ -654,7 +654,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
 
 static int velocity_soft_reset(struct velocity_info *vptr)
 {
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        int i = 0;
 
        writel(CR0_SFRST, &regs->CR0Set);
@@ -690,7 +690,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
        int i;
        struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data;
        struct velocity_info *vptr;
-       struct mac_regs * regs;
+       struct mac_regs __iomem * regs;
        int ret = -ENOMEM;
 
        if (velocity_nics >= MAX_UNITS) {
@@ -1007,7 +1007,7 @@ static void velocity_free_rings(struct velocity_info *vptr)
 
 static inline void velocity_give_many_rx_descs(struct velocity_info *vptr)
 {
-       struct mac_regs *regs = vptr->mac_regs;
+       struct mac_regs __iomem *regs = vptr->mac_regs;
        int avail, dirty, unusable;
 
        /*
@@ -1608,7 +1608,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
 {
 
        if (status & ISR_TXSTLI) {
-               struct mac_regs * regs = vptr->mac_regs;
+               struct mac_regs __iomem * regs = vptr->mac_regs;
 
                printk(KERN_ERR "TD structure errror TDindex=%hx\n", readw(&regs->TDIdx[0]));
                BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
@@ -1620,7 +1620,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
        }
 
        if (status & ISR_SRCI) {
-               struct mac_regs * regs = vptr->mac_regs;
+               struct mac_regs __iomem * regs = vptr->mac_regs;
                int linked;
 
                if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
@@ -1838,7 +1838,7 @@ out_unlock:
  
 static void velocity_shutdown(struct velocity_info *vptr)
 {
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        mac_disable_int(regs);
        writel(CR0_STOP, &regs->CR0Set);
        writew(0xFFFF, &regs->TDCSRClr);
@@ -2097,7 +2097,7 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
 static void velocity_set_multi(struct net_device *dev)
 {
        struct velocity_info *vptr = dev->priv;
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        u8 rx_mode;
        int i;
        struct dev_mc_list *mclist;
@@ -2351,7 +2351,7 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
  *     Turn off the autopoll and wait for it to disable on the chip
  */
  
-static void safe_disable_mii_autopoll(struct mac_regs * regs)
+static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs)
 {
        u16 ww;
 
@@ -2372,7 +2372,7 @@ static void safe_disable_mii_autopoll(struct mac_regs * regs)
  *     hardware. Wait for it to enable.
  */
 
-static void enable_mii_autopoll(struct mac_regs * regs)
+static void enable_mii_autopoll(struct mac_regs __iomem * regs)
 {
        int ii;
 
@@ -2405,7 +2405,7 @@ static void enable_mii_autopoll(struct mac_regs * regs)
  *     on success or -ETIMEDOUT if the PHY did not respond.
  */
  
-static int velocity_mii_read(struct mac_regs regs, u8 index, u16 *data)
+static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
 {
        u16 ww;
 
@@ -2441,7 +2441,7 @@ static int velocity_mii_read(struct mac_regs * regs, u8 index, u16 *data)
  *     on success or -ETIMEDOUT if the PHY did not respond.
  */
  
-static int velocity_mii_write(struct mac_regs regs, u8 mii_addr, u16 data)
+static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
 {
        u16 ww;
 
@@ -2576,7 +2576,7 @@ static void set_mii_flow_control(struct velocity_info *vptr)
 static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
 {
        u32 curr_status;
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
 
        vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
        curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
@@ -2683,7 +2683,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
  *     accordingly
  */
  
-static u32 mii_check_media_mode(struct mac_regs * regs)
+static u32 mii_check_media_mode(struct mac_regs __iomem * regs)
 {
        u32 status = 0;
        u16 ANAR;
@@ -2719,7 +2719,7 @@ static u32 mii_check_media_mode(struct mac_regs * regs)
        return status;
 }
 
-static u32 check_connection_type(struct mac_regs * regs)
+static u32 check_connection_type(struct mac_regs __iomem * regs)
 {
        u32 status = 0;
        u8 PHYSR0;
@@ -2764,7 +2764,7 @@ static u32 check_connection_type(struct mac_regs * regs)
 static void enable_flow_control_ability(struct velocity_info *vptr)
 {
 
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
 
        switch (vptr->options.flow_cntl) {
 
@@ -2841,7 +2841,7 @@ static void velocity_ethtool_down(struct net_device *dev)
 static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct velocity_info *vptr = dev->priv;
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        u32 status;
        status = check_connection_type(vptr->mac_regs);
 
@@ -2889,7 +2889,7 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
 static u32 velocity_get_link(struct net_device *dev)
 {
        struct velocity_info *vptr = dev->priv;
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0)  ? 0 : 1;
 }
 
@@ -2985,7 +2985,7 @@ static struct ethtool_ops velocity_ethtool_ops = {
 static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct velocity_info *vptr = dev->priv;
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        unsigned long flags;
        struct mii_ioctl_data *miidata = if_mii(ifr);
        int err;
@@ -3031,9 +3031,9 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd
  
 static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
 {
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        u16 i;
-       u8 *ptr = (u8 *)regs;
+       u8 __iomem *ptr = (u8 __iomem *)regs;
 
        for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
                *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
@@ -3057,9 +3057,9 @@ static void velocity_save_context(struct velocity_info *vptr, struct velocity_co
  
 static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
 {
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        int i;
-       u8 *ptr = (u8 *)regs;
+       u8 __iomem *ptr = (u8 __iomem *)regs;
 
        for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) {
                writel(*((u32 *) (context->mac_reg + i)), ptr + i);
@@ -3135,7 +3135,7 @@ u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
 
 static int velocity_set_wol(struct velocity_info *vptr)
 {
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
        static u8 buf[256];
        int i;
 
@@ -3221,7 +3221,7 @@ static int velocity_suspend(struct pci_dev *pdev, u32 state)
        netif_device_detach(vptr->dev);
 
        spin_lock_irqsave(&vptr->lock, flags);
-       pci_save_state(pdev, vptr->pci_state);
+       pci_save_state(pdev);
 #ifdef ETHTOOL_GWOL
        if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
                velocity_get_ip(vptr);
@@ -3254,7 +3254,7 @@ static int velocity_resume(struct pci_dev *pdev)
 
        pci_set_power_state(pdev, 0);
        pci_enable_wake(pdev, 0, 0);
-       pci_restore_state(pdev, vptr->pci_state);
+       pci_restore_state(pdev);
 
        mac_wol_reset(vptr->mac_regs);
 
index 9a187de..626e84f 100644 (file)
@@ -1270,7 +1270,7 @@ enum velocity_cam_type {
  *     provided mask buffer.
  */
 
-static inline void mac_get_cam_mask(struct mac_regs * regs, u8 * mask, enum velocity_cam_type cam_type)
+static inline void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type)
 {
        int i;
        /* Select CAM mask */
@@ -1302,7 +1302,7 @@ static inline void mac_get_cam_mask(struct mac_regs * regs, u8 * mask, enum velo
  *     Store a new mask into a CAM
  */
 
-static inline void mac_set_cam_mask(struct mac_regs * regs, u8 * mask, enum velocity_cam_type cam_type)
+static inline void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type)
 {
        int i;
        /* Select CAM mask */
@@ -1333,7 +1333,7 @@ static inline void mac_set_cam_mask(struct mac_regs * regs, u8 * mask, enum velo
  *     Load an address or vlan tag into a CAM
  */
 
-static inline void mac_set_cam(struct mac_regs * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
+static inline void mac_set_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
 {
        int i;
 
@@ -1375,7 +1375,7 @@ static inline void mac_set_cam(struct mac_regs * regs, int idx, u8 *addr, enum v
  *     the caller. VLAN tags are 2 bytes the address cam entries are 6.
  */
 
-static inline void mac_get_cam(struct mac_regs * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
+static inline void mac_get_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
 {
        int i;
 
@@ -1414,7 +1414,7 @@ static inline void mac_get_cam(struct mac_regs * regs, int idx, u8 *addr, enum v
  *     the rest of the logic from the result of sleep/wakeup
  */
 
-inline static void mac_wol_reset(struct mac_regs * regs)
+inline static void mac_wol_reset(struct mac_regs __iomem * regs)
 {
 
        /* Turn off SWPTAG right after leaving power mode */
@@ -1739,10 +1739,6 @@ struct velocity_info {
        struct net_device *dev;
        struct net_device_stats stats;
 
-#ifdef CONFIG_PM
-       u32 pci_state[16];
-#endif
-
        dma_addr_t rd_pool_dma;
        dma_addr_t td_pool_dma[TX_QUEUE_NO];
 
@@ -1752,7 +1748,7 @@ struct velocity_info {
        u8 ip_addr[4];
        enum chip_type chip_id;
 
-       struct mac_regs * mac_regs;
+       struct mac_regs __iomem * mac_regs;
        unsigned long memaddr;
        unsigned long ioaddr;
        u32 io_size;
@@ -1865,7 +1861,7 @@ static inline void velocity_update_hw_mibs(struct velocity_info *vptr)
 
 static inline void init_flow_control_register(struct velocity_info *vptr)
 {
-       struct mac_regs * regs = vptr->mac_regs;
+       struct mac_regs __iomem * regs = vptr->mac_regs;
 
        /* Set {XHITH1, XHITH0, XLTH1, XLTH0} in FlowCR1 to {1, 0, 1, 1}
           depend on RD=64, and Turn on XNOEN in FlowCR1 */
index e59ad5f..6e74af6 100644 (file)
@@ -70,8 +70,8 @@ MODULE_LICENSE("GPL");
 static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len);
 static void cycx_bootcfg(struct cycx_hw *hw);
 
-static int reset_cyc2x(void *addr);
-static int detect_cyc2x(void *addr);
+static int reset_cyc2x(void __iomem *addr);
+static int detect_cyc2x(void __iomem *addr);
 
 /* Miscellaneous functions */
 static void delay_cycx(int sec);
@@ -135,9 +135,8 @@ void cycx_drv_cleanup(void)
  * Return:     0       ok.
  *             < 0     error */
 EXPORT_SYMBOL(cycx_setup);
-int cycx_setup(struct cycx_hw *hw, void *cfm, u32 len)
+int cycx_setup(struct cycx_hw *hw, void *cfm, u32 len, unsigned long dpmbase)
 {
-       long dpmbase = (long)hw->dpmbase;
        int err;
 
        /* Verify IRQ configuration options */
@@ -203,7 +202,7 @@ void cycx_intr(struct cycx_hw *hw)
  * o Set exec flag.
  * o Busy-wait until flag is reset. */
 EXPORT_SYMBOL(cycx_exec);
-int cycx_exec(void *addr)
+int cycx_exec(void __iomem *addr)
 {
        u16 i = 0;
        /* wait till addr content is zeroed */
@@ -249,7 +248,7 @@ int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len)
 /* Load Aux Routines */
 /* Reset board hardware.
    return 1 if memory exists at addr and 0 if not. */
-static int memory_exists(void *addr)
+static int memory_exists(void __iomem *addr)
 {
        int tries = 0;
 
@@ -267,9 +266,9 @@ static int memory_exists(void *addr)
 }
 
 /* Load reset code. */
-static void reset_load(void *addr, u8 *buffer, u32 cnt)
+static void reset_load(void __iomem *addr, u8 *buffer, u32 cnt)
 {
-       void *pt_code = addr + RESET_OFFSET;
+       void __iomem *pt_code = addr + RESET_OFFSET;
        u16 i; /*, j; */
 
        for (i = 0 ; i < cnt ; i++) {
@@ -281,7 +280,7 @@ static void reset_load(void *addr, u8 *buffer, u32 cnt)
 /* Load buffer using boot interface.
  * o copy data from buffer to Cyclom-X memory
  * o wait for reset code to copy it to right portion of memory */
-static int buffer_load(void *addr, u8 *buffer, u32 cnt)
+static int buffer_load(void __iomem *addr, u8 *buffer, u32 cnt)
 {
        memcpy_toio(addr + DATA_OFFSET, buffer, cnt);
        writew(GEN_BOOT_DAT, addr + CMD_OFFSET);
@@ -290,7 +289,7 @@ static int buffer_load(void *addr, u8 *buffer, u32 cnt)
 }
 
 /* Set up entry point and kick start Cyclom-X CPU. */
-static void cycx_start(void *addr)
+static void cycx_start(void __iomem *addr)
 {
        /* put in 0x30 offset the jump instruction to the code entry point */
        writeb(0xea, addr + 0x30);
@@ -304,9 +303,9 @@ static void cycx_start(void *addr)
 }
 
 /* Load and boot reset code. */
-static void cycx_reset_boot(void *addr, u8 *code, u32 len)
+static void cycx_reset_boot(void __iomem *addr, u8 *code, u32 len)
 {
-       void *pt_start = addr + START_OFFSET;
+       void __iomem *pt_start = addr + START_OFFSET;
 
        writeb(0xea, pt_start++); /* jmp to f000:3f00 */
        writeb(0x00, pt_start++);
@@ -321,9 +320,9 @@ static void cycx_reset_boot(void *addr, u8 *code, u32 len)
 }
 
 /* Load data.bin file through boot (reset) interface. */
-static int cycx_data_boot(void *addr, u8 *code, u32 len)
+static int cycx_data_boot(void __iomem *addr, u8 *code, u32 len)
 {
-       void *pt_boot_cmd = addr + CMD_OFFSET;
+       void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
        u32 i;
 
        /* boot buffer lenght */
@@ -352,9 +351,9 @@ static int cycx_data_boot(void *addr, u8 *code, u32 len)
 
 
 /* Load code.bin file through boot (reset) interface. */
-static int cycx_code_boot(void *addr, u8 *code, u32 len)
+static int cycx_code_boot(void __iomem *addr, u8 *code, u32 len)
 {
-       void *pt_boot_cmd = addr + CMD_OFFSET;
+       void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
        u32 i;
 
        /* boot buffer lenght */
@@ -391,7 +390,7 @@ static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len)
        u8 *reset_image,
           *data_image,
           *code_image;
-       void *pt_cycld = hw->dpmbase + 0x400;
+       void __iomem *pt_cycld = hw->dpmbase + 0x400;
        u16 cksum;
 
        /* Announce */
@@ -523,7 +522,7 @@ static void cycx_bootcfg(struct cycx_hw *hw)
  *     Return 1 if detected o.k. or 0 if failed.
  *     Note:   This test is destructive! Adapter will be left in shutdown
  *             state after the test. */
-static int detect_cyc2x(void *addr)
+static int detect_cyc2x(void __iomem *addr)
 {
        reset_cyc2x(addr);
 
@@ -545,7 +544,7 @@ static int get_option_index(long *optlist, long optval)
 }
 
 /* Reset adapter's CPU. */
-static int reset_cyc2x(void *addr)
+static int reset_cyc2x(void __iomem *addr)
 {
        writeb(0, addr + RST_ENABLE);
        delay_cycx(2);
index 20b6a29..3dadcb4 100644 (file)
@@ -223,13 +223,12 @@ static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf)
        /* Configure hardware, load firmware, etc. */
        memset(&card->hw, 0, sizeof(card->hw));
        card->hw.irq     = irq;
-       card->hw.dpmbase = (void *)conf->maddr;
        card->hw.dpmsize = CYCX_WINDOWSIZE;
        card->hw.fwid    = CFID_X25_2X;
-       card->lock       = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&card->lock);
        init_waitqueue_head(&card->wait_stats);
 
-       rc = cycx_setup(&card->hw, conf->data, conf->data_size);
+       rc = cycx_setup(&card->hw, conf->data, conf->data_size, conf->maddr);
        if (rc)
                goto out_irq;
 
index 07bfe10..5b48cd8 100644 (file)
@@ -92,6 +92,8 @@
 #include <linux/cyclomx.h>     /* Cyclom 2X common user API definitions */
 #include <linux/cycx_x25.h>    /* X.25 firmware API definitions */
 
+#include <net/x25device.h>
+
 /* Defines & Macros */
 #define CYCX_X25_MAX_CMD_RETRY 5
 #define CYCX_X25_CHAN_MTU 2048 /* unfragmented logical channel MTU */
@@ -231,7 +233,7 @@ int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf)
        /* Initialize protocol-specific fields */
        card->mbox  = card->hw.dpmbase + X25_MBOX_OFFS;
        card->u.x.connection_keys = 0;
-       card->u.x.lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&card->u.x.lock);
 
        /* Configure adapter. Here we set reasonable defaults, then parse
         * device configuration structure and set configuration options.
@@ -1195,7 +1197,7 @@ static int x25_place_call(struct cycx_device *card,
             remotelen = strlen(chan->addr);
        u8 key;
 
-       if (card->u.x.connection_keys == ~0UL) {
+       if (card->u.x.connection_keys == ~0U) {
                printk(KERN_INFO "%s: too many simultaneous connection "
                                 "requests!\n", card->devname);
                return -EAGAIN;
@@ -1486,11 +1488,7 @@ static void cycx_x25_chan_send_event(struct net_device *dev, u8 event)
        ptr  = skb_put(skb, 1);
        *ptr = event;
 
-       skb->dev = dev;
-       skb->protocol = htons(ETH_P_X25);
-       skb->mac.raw = skb->data;
-       skb->pkt_type = PACKET_HOST;
-
+       skb->protocol = x25_type_trans(skb, dev);
        netif_rx(skb);
        dev->last_rx = jiffies;         /* timestamp */
 }
index bad0d41..6e1ec5b 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/if_frad.h>
+#include <linux/bitops.h>
 
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
index 5231063..07e5eef 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/rtnetlink.h>
 #include <linux/hdlc.h>
 
+#include <net/x25device.h>
+
 /* These functions are callbacks called by LAPB layer */
 
 static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
@@ -38,11 +40,7 @@ static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
        ptr = skb_put(skb, 1);
        *ptr = code;
 
-       skb->dev = dev;
-       skb->protocol = htons(ETH_P_X25);
-       skb->mac.raw = skb->data;
-       skb->pkt_type = PACKET_HOST;
-
+       skb->protocol = x25_type_trans(skb, dev);
        netif_rx(skb);
 }
 
@@ -74,11 +72,7 @@ static int x25_data_indication(struct net_device *dev, struct sk_buff *skb)
        ptr  = skb->data;
        *ptr = 0;
 
-       skb->dev = dev;
-       skb->protocol = htons(ETH_P_X25);
-       skb->mac.raw = skb->data;
-       skb->pkt_type = PACKET_HOST;
-
+       skb->protocol = x25_type_trans(skb, dev);
        return netif_rx(skb);
 }
 
index c8f3187..7f2e365 100644 (file)
@@ -43,6 +43,8 @@
 #include <linux/lapb.h>
 #include <linux/init.h>
 
+#include <net/x25device.h>
+
 static char bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
 /* If this number is made larger, check that the temporary string buffer
@@ -137,11 +139,7 @@ static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb)
        ptr  = skb->data;
        *ptr = 0x00;
 
-       skb->dev      = dev;
-       skb->protocol = htons(ETH_P_X25);
-       skb->mac.raw  = skb->data;
-       skb->pkt_type = PACKET_HOST;
-
+       skb->protocol = x25_type_trans(skb, dev);
        skb->dev->last_rx = jiffies;
        return netif_rx(skb);
 }
@@ -233,11 +231,7 @@ static void lapbeth_connected(struct net_device *dev, int reason)
        ptr  = skb_put(skb, 1);
        *ptr = 0x01;
 
-       skb->dev      = dev;
-       skb->protocol = htons(ETH_P_X25);
-       skb->mac.raw  = skb->data;
-       skb->pkt_type = PACKET_HOST;
-
+       skb->protocol = x25_type_trans(skb, dev);
        skb->dev->last_rx = jiffies;
        netif_rx(skb);
 }
@@ -255,11 +249,7 @@ static void lapbeth_disconnected(struct net_device *dev, int reason)
        ptr  = skb_put(skb, 1);
        *ptr = 0x02;
 
-       skb->dev      = dev;
-       skb->protocol = htons(ETH_P_X25);
-       skb->mac.raw  = skb->data;
-       skb->pkt_type = PACKET_HOST;
-
+       skb->protocol = x25_type_trans(skb, dev);
        skb->dev->last_rx = jiffies;
        netif_rx(skb);
 }
index 2aca8dc..f55ce76 100644 (file)
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/inet.h>
+#include <linux/bitops.h>
 
 #include <net/syncppp.h>
 
 #include <asm/processor.h>             /* Processor type for cache alignment. */
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
index a4bfff8..73401b0 100644 (file)
 
 #ifndef CY_TYPES
 #define CY_TYPES
-#if defined(__alpha__)
-typedef        unsigned long   ucdouble;       /* 64 bits, unsigned */
-typedef        unsigned int    uclong;         /* 32 bits, unsigned */
-#else
-typedef        unsigned long   uclong;         /* 32 bits, unsigned */
-#endif
-typedef        unsigned short  ucshort;        /* 16 bits, unsigned */
-typedef        unsigned char   ucchar;         /* 8 bits, unsigned */
+typedef        __u64   ucdouble;       /* 64 bits, unsigned */
+typedef        __u32   uclong;         /* 32 bits, unsigned */
+typedef        __u16   ucshort;        /* 16 bits, unsigned */
+typedef        __u8    ucchar;         /* 8 bits, unsigned */
 #endif /* CY_TYPES */
 
 #define PC300_PROTO_MLPPP 1            
index 7a972ca..59b7d57 100644 (file)
@@ -378,9 +378,9 @@ static void tx_dma_buf_check(pc300_t * card, int ch)
             i != ((next_bd + 1) & (N_DMA_TX_BUF - 1));
             i = (i + 1) & (N_DMA_TX_BUF - 1), 
                 ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i))) {
-               printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d",
-                      ch, i, (uclong) cpc_readl(&ptdescr->next),
-                      (uclong) cpc_readl(&ptdescr->ptbuf),
+               printk("\n CH%d TX%d: next=0x%x, ptbuf=0x%x, ST=0x%x, len=%d",
+                      ch, i, cpc_readl(&ptdescr->next),
+                      cpc_readl(&ptdescr->ptbuf),
                       cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len));
        }
        printk("\n");
@@ -400,14 +400,14 @@ static void tx1_dma_buf_check(pc300_t * card, int ch)
        printk("#CH%d: f_bd = %d(0x%08x), n_bd = %d(0x%08x)\n", ch,
               first_bd, TX_BD_ADDR(ch, first_bd),
               next_bd, TX_BD_ADDR(ch, next_bd));
-       printk("TX_CDA=0x%08lx, TX_EDA=0x%08lx\n",
-              (uclong) cpc_readl(scabase + DTX_REG(CDAL, ch)),
-              (uclong) cpc_readl(scabase + DTX_REG(EDAL, ch)));
+       printk("TX_CDA=0x%08x, TX_EDA=0x%08x\n",
+              cpc_readl(scabase + DTX_REG(CDAL, ch)),
+              cpc_readl(scabase + DTX_REG(EDAL, ch)));
        for (i = 0; i < N_DMA_TX_BUF; i++) {
                ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i));
-               printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d",
-                      ch, i, (uclong) cpc_readl(&ptdescr->next),
-                      (uclong) cpc_readl(&ptdescr->ptbuf),
+               printk("\n CH%d TX%d: next=0x%x, ptbuf=0x%x, ST=0x%x, len=%d",
+                      ch, i, cpc_readl(&ptdescr->next),
+                      cpc_readl(&ptdescr->ptbuf),
                       cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len));
        }
        printk("\n");
@@ -428,9 +428,9 @@ static void rx_dma_buf_check(pc300_t * card, int ch)
                                              DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
             i < N_DMA_RX_BUF; i++, ptdescr++) {
                if (cpc_readb(&ptdescr->status) & DST_OSB)
-                       printk ("\n CH%d RX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d",
-                                ch, i, (uclong) cpc_readl(&ptdescr->next),
-                                (uclong) cpc_readl(&ptdescr->ptbuf),
+                       printk ("\n CH%d RX%d: next=0x%x, ptbuf=0x%x, ST=0x%x, len=%d",
+                                ch, i, cpc_readl(&ptdescr->next),
+                                cpc_readl(&ptdescr->ptbuf),
                                 cpc_readb(&ptdescr->status),
                                 cpc_readw(&ptdescr->len));
        }
@@ -1959,7 +1959,6 @@ void cpc_net_rx(struct net_device *dev)
                        cpc_trace(dev, skb, 'R');
                }
                stats->rx_packets++;
-               skb->mac.raw = skb->data;
                skb->protocol = hdlc_type_trans(skb, dev);
                netif_rx(skb);
        }
@@ -2416,12 +2415,12 @@ void cpc_sca_status(pc300_t * card, int ch)
        printk ("ILAR=0x%02x, WCRL=0x%02x, PCR=0x%02x, BTCR=0x%02x, BOLR=0x%02x\n",
                 ilar, cpc_readb(scabase + WCRL), cpc_readb(scabase + PCR),
                 cpc_readb(scabase + BTCR), cpc_readb(scabase + BOLR));
-       printk("TX_CDA=0x%08lx, TX_EDA=0x%08lx\n",
-              (uclong) cpc_readl(scabase + DTX_REG(CDAL, ch)),
-              (uclong) cpc_readl(scabase + DTX_REG(EDAL, ch)));
-       printk("RX_CDA=0x%08lx, RX_EDA=0x%08lx, BFL=0x%04x\n",
-              (uclong) cpc_readl(scabase + DRX_REG(CDAL, ch)),
-              (uclong) cpc_readl(scabase + DRX_REG(EDAL, ch)),
+       printk("TX_CDA=0x%08x, TX_EDA=0x%08x\n",
+              cpc_readl(scabase + DTX_REG(CDAL, ch)),
+              cpc_readl(scabase + DTX_REG(EDAL, ch)));
+       printk("RX_CDA=0x%08x, RX_EDA=0x%08x, BFL=0x%04x\n",
+              cpc_readl(scabase + DRX_REG(CDAL, ch)),
+              cpc_readl(scabase + DRX_REG(EDAL, ch)),
               cpc_readw(scabase + DRX_REG(BFLL, ch)));
        printk("DMER=0x%02x, DSR_TX=0x%02x, DSR_RX=0x%02x\n",
               cpc_readb(scabase + DMER), cpc_readb(scabase + DSR_TX(ch)),
@@ -2486,7 +2485,7 @@ void cpc_sca_status(pc300_t * card, int ch)
               cpc_readb(scabase + M_REG(IE2, ch)),
               cpc_readb(scabase + M_REG(IE4, ch)),
               cpc_readb(scabase + M_REG(FIE, ch)));
-       printk("IER0=0x%08lx\n", (uclong) cpc_readl(scabase + IER0));
+       printk("IER0=0x%08x\n", cpc_readl(scabase + IER0));
 
        if (ilar != 0) {
                CPC_LOCK(card, flags);
@@ -3407,12 +3406,12 @@ static void cpc_init_card(pc300_t * card)
                                        printk("RSV ");
                                        break;
                        }
-                       printk (" #%d, %ldKB of RAM at 0x%08lx, IRQ%d, channel %d.\n",
+                       printk (" #%d, %dKB of RAM at 0x%08x, IRQ%d, channel %d.\n",
                                 board_nbr, card->hw.ramsize / 1024,
                                 card->hw.ramphys, card->hw.irq, i + 1);
                        devcount++;
                } else {
-                       printk ("Dev%d on card(0x%08lx): unable to allocate i/f name.\n",
+                       printk ("Dev%d on card(0x%08x): unable to allocate i/f name.\n",
                                 i + 1, card->hw.ramphys);
                        free_netdev(dev);
                        continue;
@@ -3492,7 +3491,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!request_region(card->hw.iophys, card->hw.iosize, "PLX Registers")) {
                /* In case we can't allocate it, warn user */
                printk("WARNING: couldn't allocate I/O region for PC300 board "
-                      "at 0x%08lx!\n", card->hw.ramphys);
+                      "at 0x%08x!\n", card->hw.ramphys);
        }
 
        if (card->hw.plxphys) {
@@ -3505,7 +3504,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        if (!request_mem_region(card->hw.plxphys, card->hw.plxsize,
                                "PLX Registers")) {
-               printk("PC300 found at RAM 0x%08lx, "
+               printk("PC300 found at RAM 0x%08x, "
                       "but could not allocate PLX mem region.\n",
                       card->hw.ramphys);
                err = -ENODEV;
@@ -3513,7 +3512,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        if (!request_mem_region(card->hw.ramphys, card->hw.alloc_ramsize,
                                "On-board RAM")) {
-               printk("PC300 found at RAM 0x%08lx, "
+               printk("PC300 found at RAM 0x%08x, "
                       "but could not allocate RAM mem region.\n",
                       card->hw.ramphys);
                err = -ENODEV;
@@ -3521,7 +3520,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        if (!request_mem_region(card->hw.scaphys, card->hw.scasize,
                                "SCA-II Registers")) {
-               printk("PC300 found at RAM 0x%08lx, "
+               printk("PC300 found at RAM 0x%08x, "
                       "but could not allocate SCA mem region.\n",
                       card->hw.ramphys);
                err = -ENODEV;
@@ -3601,7 +3600,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* Allocate IRQ */
        if (request_irq(card->hw.irq, cpc_intr, SA_SHIRQ, "Cyclades-PC300", card)) {
-               printk ("PC300 found at RAM 0x%08lx, but could not allocate IRQ%d.\n",
+               printk ("PC300 found at RAM 0x%08x, but could not allocate IRQ%d.\n",
                         card->hw.ramphys, card->hw.irq);
                goto err_io_unmap;
        }
index 1259818..f0ed00e 100644 (file)
@@ -51,9 +51,9 @@
 #include <linux/if_arp.h>
 #include <linux/if_frad.h>
 #include <linux/sdla.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
index e66c250..afbe002 100644 (file)
@@ -3739,8 +3739,7 @@ static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp)
        return 0;
 }
 
-static int wanpipe_tty_write(struct tty_struct * tty, int from_user,
-                   const unsigned char *buf, int count)
+static int wanpipe_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
 {
        unsigned long smp_flags=0;
        sdla_t *card=NULL;
@@ -3784,58 +3783,16 @@ static int wanpipe_tty_write(struct tty_struct * tty, int from_user,
                return -EINVAL; 
        }
        
-       if (from_user) {
-               
-               unsigned char *tmp_buf;
-               
-               if ((tmp_buf=card->tty_buf)==NULL){
-                       dbg_printk(KERN_INFO "No TTY BUF in Write\n");
-                       
-                       clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
-                       
-                       if(card->hw.type != SDLA_S514)
-                               s508_unlock(card,&smp_flags);
-                       
-                       return -ENOMEM;
-               }
-               
-               if (copy_from_user(tmp_buf,buf,count)){
-                       dbg_printk(KERN_INFO "%s: Failed to copy from user!\n",
-                                       card->devname);
-                       
-                       clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
-                       
-                       if(card->hw.type != SDLA_S514)
-                               s508_unlock(card,&smp_flags);
-                       
-                       return -EINVAL;
-               }
-
-               if (chdlc_send(card,(void*)tmp_buf,count)){
-                       dbg_printk(KERN_INFO "%s: Failed to send, retry later: user!\n",
-                                       card->devname);
-                       
-                       clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
-                       
-                       wanpipe_tty_trigger_tx_irq(card);
-                       
-                       if(card->hw.type != SDLA_S514)
-                               s508_unlock(card,&smp_flags);
-                       return 0;
-               }
+       if (chdlc_send(card,(void*)buf,count)){
+               dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n",
+                               card->devname);
+               clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
 
-       }else{
-               if (chdlc_send(card,(void*)buf,count)){
-                       dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n",
-                                       card->devname);
-                       clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
-       
-                       wanpipe_tty_trigger_tx_irq(card);
-                       
-                       if(card->hw.type != SDLA_S514)
-                               s508_unlock(card,&smp_flags);
-                       return 0;
-               }
+               wanpipe_tty_trigger_tx_irq(card);
+               
+               if(card->hw.type != SDLA_S514)
+                       s508_unlock(card,&smp_flags);
+               return 0;
        }
        dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count);
        clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
index a48af69..e499f4b 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/timer.h>
 
 #include <linux/init.h>
+#include <linux/bitops.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
index 1364114..f016342 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 #ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>
 #if WIRELESS_EXT > 12
@@ -70,7 +71,6 @@
 #include <pcmcia/mem_op.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
@@ -219,7 +219,6 @@ static void netwave_reset(struct net_device *dev);
 /* Misc device stuff */
 static int netwave_open(struct net_device *dev);  /* Open the device */
 static int netwave_close(struct net_device *dev); /* Close the device */
-static int netwave_config(struct net_device *dev, struct ifmap *map);
 
 /* Packet transmission and Packet reception */
 static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
@@ -482,7 +481,6 @@ static dev_link_t *netwave_attach(void)
     /* Netwave specific entries in the device structure */
     SET_MODULE_OWNER(dev);
     dev->hard_start_xmit = &netwave_start_xmit;
-    dev->set_config = &netwave_config;
     dev->get_stats  = &netwave_get_stats;
     dev->set_multicast_list = &set_multicast_list;
     /* wireless extensions */
@@ -1288,16 +1286,6 @@ static void netwave_reset(struct net_device *dev) {
     outb(corConfIENA + corConfLVLREQ, iobase + NETWAVE_REG_COR);
 }
 
-/*
- * Function netwave_config (dev, map)
- *
- *    Configure device, this work is done by netwave_pcmcia_config when a
- *    card is inserted
- */
-static int netwave_config(struct net_device *dev, struct ifmap *map) {
-    return 0; 
-}
-
 /*
  * Function netwave_hw_xmit (data, len, dev)    
  */
index 3047d8c..2562c1d 100644 (file)
@@ -2172,6 +2172,11 @@ static int wavelan_get_range(struct net_device *dev,
        range->num_bitrates = 1;
        range->bitrate[0] = 2000000;    /* 2 Mb/s */
 
+       /* Event capability (kernel + driver) */
+       range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) |
+                               IW_EVENT_CAPA_MASK(0x8B04));
+       range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
        /* Disable interrupts and save flags. */
        spin_lock_irqsave(&lp->spinlock, flags);
        
@@ -2403,11 +2408,10 @@ static const struct iw_handler_def      wavelan_handler_def =
        .num_standard   = sizeof(wavelan_handler)/sizeof(iw_handler),
        .num_private    = sizeof(wavelan_private_handler)/sizeof(iw_handler),
        .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
-       .standard       = (iw_handler *) wavelan_handler,
-       .private        = (iw_handler *) wavelan_private_handler,
-       .private_args   = (struct iw_priv_args *) wavelan_private_args,
-       .spy_offset     = ((void *) (&((net_local *) NULL)->spy_data) -
-                          (void *) NULL),
+       .standard       = wavelan_handler,
+       .private        = wavelan_private_handler,
+       .private_args   = wavelan_private_args,
+       .get_wireless_stats = wavelan_get_wireless_stats,
 };
 
 /*------------------------------------------------------------------*/
@@ -4191,8 +4195,9 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr)
 #endif                         /* SET_MAC_ADDRESS */
 
 #ifdef WIRELESS_EXT            /* if wireless extension exists in the kernel */
-       dev->get_wireless_stats = wavelan_get_wireless_stats;
-       dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
+       dev->wireless_handlers = &wavelan_handler_def;
+       lp->wireless_data.spy_data = &lp->spy_data;
+       dev->wireless_data = &lp->wireless_data;
 #endif
 
        dev->mtu = WAVELAN_MTU;
index d35ac4d..475add6 100644 (file)
 #include       <linux/in.h>
 #include       <linux/string.h>
 #include       <linux/delay.h>
+#include       <linux/bitops.h>
 #include       <asm/system.h>
-#include       <asm/bitops.h>
 #include       <asm/io.h>
 #include       <asm/dma.h>
 #include       <asm/uaccess.h>
@@ -510,6 +510,7 @@ struct net_local
   iw_stats     wstats;         /* Wireless-specific statistics */
 
   struct iw_spy_data   spy_data;
+  struct iw_public_data        wireless_data;
 #endif
 
 #ifdef HISTOGRAM
@@ -614,6 +615,8 @@ static inline void
 /* ------------------- IOCTL, STATS & RECONFIG ------------------- */
 static en_stats        *
        wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */
+static iw_stats *
+       wavelan_get_wireless_stats(struct net_device *);
 static void
        wavelan_set_multicast_list(struct net_device *);
 /* ----------------------- PACKET RECEPTION ----------------------- */
index 5eb32a9..0579717 100644 (file)
@@ -502,7 +502,7 @@ unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00};
   
 void wv_roam_init(struct net_device *dev)
 {
-  net_local  *lp= (net_local *)dev->priv;
+  net_local  *lp= netdev_priv(dev);
 
   /* Do not remove this unless you have a good reason */
   printk(KERN_NOTICE "%s: Warning, you have enabled roaming on"
@@ -532,7 +532,7 @@ void wv_roam_init(struct net_device *dev)
 void wv_roam_cleanup(struct net_device *dev)
 {
   wavepoint_history *ptr,*old_ptr;
-  net_local *lp= (net_local *)dev->priv;
+  net_local *lp= netdev_priv(dev);
   
   printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name);
   
@@ -762,7 +762,7 @@ static inline void wl_roam_gather(struct net_device *  dev,
   unsigned short nwid=ntohs(beacon->nwid);  
   unsigned short sigqual=stats[2] & MMR_SGNL_QUAL;   /* SNR of beacon */
   wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
-  net_local *lp=(net_local *)dev->priv;              /* Device info */
+  net_local *lp = netdev_priv(dev);              /* Device info */
 
 #ifdef I_NEED_THIS_FEATURE
   /* Some people don't need this, some other may need it */
@@ -1006,7 +1006,7 @@ read_ringbuf(struct net_device *  dev,
 static inline void
 wv_82593_reconfig(struct net_device *  dev)
 {
-  net_local *          lp = (net_local *)dev->priv;
+  net_local *          lp = netdev_priv(dev);
   dev_link_t *         link = lp->link;
   unsigned long                flags;
 
@@ -1135,7 +1135,7 @@ static void
 wv_mmc_show(struct net_device *        dev)
 {
   ioaddr_t     base = dev->base_addr;
-  net_local *  lp = (net_local *)dev->priv;
+  net_local *  lp = netdev_priv(dev);
   mmr_t                m;
 
   /* Basic check */
@@ -1224,7 +1224,7 @@ wv_mmc_show(struct net_device *   dev)
 static void
 wv_ru_show(struct net_device * dev)
 {
-  net_local *lp = (net_local *) dev->priv;
+  net_local *lp = netdev_priv(dev);
 
   printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n");
   printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop);
@@ -1258,9 +1258,7 @@ wv_dev_show(struct net_device *   dev)
 static void
 wv_local_show(struct net_device *      dev)
 {
-  net_local *lp;
-
-  lp = (net_local *)dev->priv;
+  net_local *lp = netdev_priv(dev);
 
   printk(KERN_DEBUG "local:");
   /*
@@ -1418,7 +1416,7 @@ wavelan_get_stats(struct net_device *     dev)
   printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
 #endif
 
-  return(&((net_local *) dev->priv)->stats);
+  return(&((net_local *)netdev_priv(dev))->stats);
 }
 
 /*------------------------------------------------------------------*/
@@ -1433,7 +1431,7 @@ wavelan_get_stats(struct net_device *     dev)
 static void
 wavelan_set_multicast_list(struct net_device * dev)
 {
-  net_local *  lp = (net_local *) dev->priv;
+  net_local *  lp = netdev_priv(dev);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);
@@ -1550,7 +1548,6 @@ wavelan_set_mac_address(struct net_device *       dev,
 /*
  * Frequency setting (for hardware able of it)
  * It's a bit complicated and you don't really want to look into it...
- * (called in wavelan_ioctl)
  */
 static inline int
 wv_set_frequency(u_long                base,   /* i/o port of the card */
@@ -1826,7 +1823,7 @@ static inline void
 wl_his_gather(struct net_device *      dev,
              u_char *  stats)          /* Statistics to gather */
 {
-  net_local *  lp = (net_local *) dev->priv;
+  net_local *  lp = netdev_priv(dev);
   u_char       level = stats[0] & MMR_SIGNAL_LVL;
   int          i;
 
@@ -1840,28 +1837,15 @@ wl_his_gather(struct net_device *       dev,
 }
 #endif /* HISTOGRAM */
 
-static inline int
-wl_netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       u32 ethcmd;
-
-       if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-               return -EFAULT;
-
-       switch (ethcmd) {
-       case ETHTOOL_GDRVINFO: {
-               struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-
-               strncpy(info.driver, "wavelan_cs", sizeof(info.driver)-1);
-               if (copy_to_user(useraddr, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       }
-
-       return -EOPNOTSUPP;
+       strncpy(info->driver, "wavelan_cs", sizeof(info->driver)-1);
 }
 
+static struct ethtool_ops ops = {
+       .get_drvinfo = wl_get_drvinfo
+};
+
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : get protocol name
@@ -1885,7 +1869,7 @@ static int wavelan_set_nwid(struct net_device *dev,
                            char *extra)
 {
        ioaddr_t base = dev->base_addr;
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        psa_t psa;
        mm_t m;
        unsigned long flags;
@@ -1943,7 +1927,7 @@ static int wavelan_get_nwid(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
        int ret = 0;
@@ -1975,7 +1959,7 @@ static int wavelan_set_freq(struct net_device *dev,
                            char *extra)
 {
        ioaddr_t base = dev->base_addr;
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        unsigned long flags;
        int ret;
 
@@ -2005,7 +1989,7 @@ static int wavelan_get_freq(struct net_device *dev,
                            char *extra)
 {
        ioaddr_t base = dev->base_addr;
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
        int ret = 0;
@@ -2051,7 +2035,7 @@ static int wavelan_set_sens(struct net_device *dev,
                            char *extra)
 {
        ioaddr_t base = dev->base_addr;
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
        int ret = 0;
@@ -2086,7 +2070,7 @@ static int wavelan_get_sens(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
        int ret = 0;
@@ -2117,7 +2101,7 @@ static int wavelan_set_encode(struct net_device *dev,
                              char *extra)
 {
        ioaddr_t base = dev->base_addr;
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        unsigned long flags;
        psa_t psa;
        int ret = 0;
@@ -2187,7 +2171,7 @@ static int wavelan_get_encode(struct net_device *dev,
                              char *extra)
 {
        ioaddr_t base = dev->base_addr;
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
        int ret = 0;
@@ -2234,7 +2218,7 @@ static int wavelan_set_essid(struct net_device *dev,
                             union iwreq_data *wrqu,
                             char *extra)
 {
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        unsigned long flags;
        int ret = 0;
 
@@ -2282,7 +2266,7 @@ static int wavelan_get_essid(struct net_device *dev,
                             union iwreq_data *wrqu,
                             char *extra)
 {
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
 
        /* Is the domain ID active ? */
        wrqu->data.flags = lp->filter_domains;
@@ -2347,7 +2331,7 @@ static int wavelan_set_mode(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        unsigned long flags;
        int ret = 0;
 
@@ -2406,7 +2390,7 @@ static int wavelan_get_range(struct net_device *dev,
                             char *extra)
 {
        ioaddr_t base = dev->base_addr;
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        struct iw_range *range = (struct iw_range *) extra;
        unsigned long flags;
        int ret = 0;
@@ -2438,6 +2422,12 @@ static int wavelan_get_range(struct net_device *dev,
        range->num_bitrates = 1;
        range->bitrate[0] = 2000000;    /* 2 Mb/s */
 
+       /* Event capability (kernel + driver) */
+       range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) |
+                               IW_EVENT_CAPA_MASK(0x8B04) |
+                               IW_EVENT_CAPA_MASK(0x8B06));
+       range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
        /* Disable interrupts and save flags. */
        spin_lock_irqsave(&lp->spinlock, flags);
        
@@ -2476,7 +2466,7 @@ static int wavelan_set_qthr(struct net_device *dev,
                            char *extra)
 {
        ioaddr_t base = dev->base_addr;
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
 
@@ -2507,7 +2497,7 @@ static int wavelan_get_qthr(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
 
@@ -2535,7 +2525,7 @@ static int wavelan_set_roam(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
        unsigned long flags;
 
        /* Disable interrupts and save flags. */
@@ -2580,7 +2570,7 @@ static int wavelan_set_histo(struct net_device *dev,
                             union iwreq_data *wrqu,
                             char *extra)
 {
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
 
        /* Check the number of intervals. */
        if (wrqu->data.length > 16) {
@@ -2623,7 +2613,7 @@ static int wavelan_get_histo(struct net_device *dev,
                             union iwreq_data *wrqu,
                             char *extra)
 {
-       net_local *lp = (net_local *) dev->priv;        /* lp is not unused */
+       net_local *lp = netdev_priv(dev);
 
        /* Set the number of intervals. */
        wrqu->data.length = lp->his_number;
@@ -2737,48 +2727,12 @@ static const struct iw_handler_def      wavelan_handler_def =
        .num_standard   = sizeof(wavelan_handler)/sizeof(iw_handler),
        .num_private    = sizeof(wavelan_private_handler)/sizeof(iw_handler),
        .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
-       .standard       = (iw_handler *) wavelan_handler,
-       .private        = (iw_handler *) wavelan_private_handler,
-       .private_args   = (struct iw_priv_args *) wavelan_private_args,
-       .spy_offset     = ((void *) (&((net_local *) NULL)->spy_data) -
-                          (void *) NULL),
+       .standard       = wavelan_handler,
+       .private        = wavelan_private_handler,
+       .private_args   = wavelan_private_args,
+       .get_wireless_stats = wavelan_get_wireless_stats,
 };
 
-/*------------------------------------------------------------------*/
-/*
- * Perform ioctl : config & info stuff
- * This is here that are treated the wireless extensions (iwconfig)
- */
-static int
-wavelan_ioctl(struct net_device *      dev,    /* Device on wich the ioctl apply */
-             struct ifreq *    rq,     /* Data passed */
-             int               cmd)    /* Ioctl number */
-{
-  int                  ret = 0;
-
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
-#endif
-
-  /* Look what is the request */
-  switch(cmd)
-    {
-    case SIOCETHTOOL:
-      ret = wl_netdev_ethtool_ioctl(dev, rq->ifr_data);
-      break;
-
-      /* ------------------- OTHER IOCTL ------------------- */
-
-    default:
-      ret = -EOPNOTSUPP;
-    }
-
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
-#endif
-  return ret;
-}
-
 /*------------------------------------------------------------------*/
 /*
  * Get wireless statistics
@@ -2788,7 +2742,7 @@ static iw_stats *
 wavelan_get_wireless_stats(struct net_device * dev)
 {
   ioaddr_t             base = dev->base_addr;
-  net_local *          lp = (net_local *) dev->priv;
+  net_local *          lp = netdev_priv(dev);
   mmr_t                        m;
   iw_stats *           wstats;
   unsigned long                flags;
@@ -2913,7 +2867,7 @@ wv_packet_read(struct net_device *                dev,
               int              fd_p,
               int              sksize)
 {
-  net_local *          lp = (net_local *) dev->priv;
+  net_local *          lp = netdev_priv(dev);
   struct sk_buff *     skb;
 
 #ifdef DEBUG_RX_TRACE
@@ -3015,7 +2969,7 @@ static inline void
 wv_packet_rcv(struct net_device *      dev)
 {
   ioaddr_t     base = dev->base_addr;
-  net_local *  lp = (net_local *) dev->priv;
+  net_local *  lp = netdev_priv(dev);
   int          newrfp;
   int          rp;
   int          len;
@@ -3150,7 +3104,7 @@ wv_packet_write(struct net_device *       dev,
                void *          buf,
                short           length)
 {
-  net_local *          lp = (net_local *) dev->priv;
+  net_local *          lp = netdev_priv(dev);
   ioaddr_t             base = dev->base_addr;
   unsigned long                flags;
   int                  clen = length;
@@ -3211,7 +3165,7 @@ static int
 wavelan_packet_xmit(struct sk_buff *   skb,
                    struct net_device *         dev)
 {
-  net_local *          lp = (net_local *)dev->priv;
+  net_local *          lp = netdev_priv(dev);
   unsigned long                flags;
 
 #ifdef DEBUG_TX_TRACE
@@ -3470,7 +3424,7 @@ static int
 wv_ru_stop(struct net_device * dev)
 {
   ioaddr_t     base = dev->base_addr;
-  net_local *  lp = (net_local *) dev->priv;
+  net_local *  lp = netdev_priv(dev);
   unsigned long        flags;
   int          status;
   int          spin;
@@ -3533,7 +3487,7 @@ static int
 wv_ru_start(struct net_device *        dev)
 {
   ioaddr_t     base = dev->base_addr;
-  net_local *  lp = (net_local *) dev->priv;
+  net_local *  lp = netdev_priv(dev);
   unsigned long        flags;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3621,7 +3575,7 @@ static int
 wv_82593_config(struct net_device *    dev)
 {
   ioaddr_t                     base = dev->base_addr;
-  net_local *                  lp = (net_local *) dev->priv;
+  net_local *                  lp = netdev_priv(dev);
   struct i82593_conf_block     cfblk;
   int                          ret = TRUE;
 
@@ -3796,7 +3750,7 @@ wv_pcmcia_reset(struct net_device *       dev)
 {
   int          i;
   conf_reg_t   reg = { 0, CS_READ, CISREG_COR, 0 };
-  dev_link_t * link = ((net_local *) dev->priv)->link;
+  dev_link_t * link = ((net_local *)netdev_priv(dev))->link;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name);
@@ -3856,7 +3810,7 @@ wv_pcmcia_reset(struct net_device *       dev)
 static int
 wv_hw_config(struct net_device *       dev)
 {
-  net_local *          lp = (net_local *) dev->priv;
+  net_local *          lp = netdev_priv(dev);
   ioaddr_t             base = dev->base_addr;
   unsigned long                flags;
   int                  ret = FALSE;
@@ -3963,7 +3917,7 @@ wv_hw_config(struct net_device *  dev)
 static inline void
 wv_hw_reset(struct net_device *        dev)
 {
-  net_local *  lp = (net_local *) dev->priv;
+  net_local *  lp = netdev_priv(dev);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
@@ -4131,8 +4085,8 @@ wv_pcmcia_config(dev_link_t *     link)
       return FALSE;
     }
 
-  strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
-  link->dev = &((net_local *) dev->priv)->node;
+  strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name);
+  link->dev = &((net_local *) netdev_priv(dev))->node;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "<-wv_pcmcia_config()\n");
@@ -4203,7 +4157,7 @@ wavelan_interrupt(int             irq,
   printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
 #endif
 
-  lp = (net_local *) dev->priv;
+  lp = netdev_priv(dev);
   base = dev->base_addr;
 
 #ifdef DEBUG_INTERRUPT_INFO
@@ -4453,7 +4407,7 @@ wavelan_interrupt(int             irq,
 static void
 wavelan_watchdog(struct net_device *   dev)
 {
-  net_local *          lp = (net_local *) dev->priv;
+  net_local *          lp = netdev_priv(dev);
   ioaddr_t             base = dev->base_addr;
   unsigned long                flags;
   int                  aborted = FALSE;
@@ -4528,8 +4482,8 @@ wavelan_watchdog(struct net_device *      dev)
 static int
 wavelan_open(struct net_device *       dev)
 {
-  dev_link_t * link = ((net_local *) dev->priv)->link;
-  net_local *  lp = (net_local *)dev->priv;
+  net_local *  lp = netdev_priv(dev);
+  dev_link_t * link = lp->link;
   ioaddr_t     base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4583,7 +4537,7 @@ wavelan_open(struct net_device *  dev)
 static int
 wavelan_close(struct net_device *      dev)
 {
-  dev_link_t * link = ((net_local *) dev->priv)->link;
+  dev_link_t * link = ((net_local *)netdev_priv(dev))->link;
   ioaddr_t     base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4686,7 +4640,7 @@ wavelan_attach(void)
   }
   link->priv = link->irq.Instance = dev;
 
-  lp = dev->priv;
+  lp = netdev_priv(dev);
 
   /* Init specific data */
   lp->configured = 0;
@@ -4718,11 +4672,12 @@ wavelan_attach(void)
   /* Set the watchdog timer */
   dev->tx_timeout      = &wavelan_watchdog;
   dev->watchdog_timeo  = WATCHDOG_JIFFIES;
+  SET_ETHTOOL_OPS(dev, &ops);
 
 #ifdef WIRELESS_EXT    /* If wireless extension exist in the kernel */
-  dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
-  dev->do_ioctl = wavelan_ioctl;       /* old wireless extensions */
-  dev->get_wireless_stats = wavelan_get_wireless_stats;
+  dev->wireless_handlers = &wavelan_handler_def;
+  lp->wireless_data.spy_data = &lp->spy_data;
+  dev->wireless_data = &lp->wireless_data;
 #endif
 
   /* Other specific data */
@@ -4820,8 +4775,8 @@ wavelan_detach(dev_link_t *       link)
       if (link->dev)
        unregister_netdev(dev);
       link->dev = NULL;
-      ((net_local *) dev->priv)->link = NULL;
-      ((net_local *) dev->priv)->dev = NULL;
+      ((net_local *)netdev_priv(dev))->link = NULL;
+      ((net_local *)netdev_priv(dev))->dev = NULL;
       free_netdev(dev);
     }
   kfree(link);
index f7dfc2f..0c18af2 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/in.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -629,6 +629,7 @@ struct net_local
   iw_stats     wstats;         /* Wireless specific stats */
 
   struct iw_spy_data   spy_data;
+  struct iw_public_data        wireless_data;
 #endif
 
 #ifdef HISTOGRAM
@@ -725,6 +726,8 @@ static inline void
 /* ------------------- IOCTL, STATS & RECONFIG ------------------- */
 static en_stats        *
        wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */
+static iw_stats *
+       wavelan_get_wireless_stats(struct net_device *);
 /* ----------------------- PACKET RECEPTION ----------------------- */
 static inline int
        wv_start_of_frame(struct net_device *,  /* Seek beggining of current frame */
index 4e62fa6..ffd8d7d 100644 (file)
@@ -1487,55 +1487,14 @@ struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
        return wstats;
 }
 
-static inline int wl3501_ethtool_ioctl(struct net_device *dev, void __user *uaddr)
+static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       u32 ethcmd;
-       int rc = -EFAULT;
-
-       if (copy_from_user(&ethcmd, uaddr, sizeof(ethcmd)))
-               goto out;
-
-       switch (ethcmd) {
-       case ETHTOOL_GDRVINFO: {
-               struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO, };
-
-               strlcpy(info.driver, wl3501_dev_info, sizeof(info.driver));
-               rc = copy_to_user(uaddr, &info, sizeof(info)) ? -EFAULT : 1;
-       }
-       default:
-               rc = -EOPNOTSUPP;
-               break;
-       }
-out:
-       return rc;
+       strlcpy(info->driver, wl3501_dev_info, sizeof(info->driver));
 }
 
-/**
- * wl3501_ioctl - Perform IOCTL call functions
- * @dev - network device
- * @ifreq - request
- * @cmd - command
- *
- * Perform IOCTL call functions here. Some are privileged operations and the
- * effective uid is checked in those cases.
- *
- * This part is optional. Needed only if you want to run wlu (unix version).
- *
- * CAUTION: To prevent interrupted by wl3501_interrupt() and timer-based
- * wl3501_hard_start_xmit() from other interrupts, this should be run
- * single-threaded.
- */
-static int wl3501_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       int rc = -ENODEV;
-
-       if (netif_device_present(dev)) {
-               rc = -EOPNOTSUPP;
-               if (cmd == SIOCETHTOOL)
-                       rc = wl3501_ethtool_ioctl(dev, rq->ifr_data);
-       }
-       return rc;
-}
+static struct ethtool_ops ops = {
+       .get_drvinfo = wl3501_get_drvinfo
+};
 
 /**
  * wl3501_detach - deletes a driver "instance"
@@ -2047,8 +2006,8 @@ static dev_link_t *wl3501_attach(void)
        dev->watchdog_timeo     = 5 * HZ;
        dev->get_stats          = wl3501_get_stats;
        dev->get_wireless_stats = wl3501_get_wireless_stats;
-       dev->do_ioctl           = wl3501_ioctl;
        dev->wireless_handlers  = (struct iw_handler_def *)&wl3501_handler_def;
+       SET_ETHTOOL_OPS(dev, &ops);
        netif_stop_queue(dev);
        link->priv = link->irq.Instance = dev;
 
index 9ebd5ea..20b2691 100644 (file)
@@ -98,9 +98,9 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
@@ -421,7 +421,7 @@ static int __init znet_probe (void)
 
        znet->rx_dma = netinfo->dma1;
        znet->tx_dma = netinfo->dma2;
-       znet->lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&znet->lock);
        znet->sia_base = 0xe6;  /* Magic address for the 82501 SIA */
        znet->sia_size = 2;
        /* maz: Despite the '593 being advertised above as using a
index 5f03189..543d2cb 100644 (file)
 #include <linux/init.h>
 #include <asm/ptrace.h>
  
-static int timer_notify(struct notifier_block * self, unsigned long val, void * data)
+static int timer_notify(struct pt_regs *regs)
 {
-       struct pt_regs * regs = (struct pt_regs *)data;
        int cpu = smp_processor_id();
        unsigned long eip = profile_pc(regs);
  
        oprofile_add_sample(eip, !user_mode(regs), 0, cpu);
        return 0;
 }
-static struct notifier_block timer_notifier = {
-       .notifier_call  = timer_notify,
-};
 
 static int timer_start(void)
 {
-       return register_profile_notifier(&timer_notifier);
+       return register_timer_hook(timer_notify);
 }
 
 
 static void timer_stop(void)
 {
-       unregister_profile_notifier(&timer_notifier);
+       unregister_timer_hook(timer_notify);
 }
 
 
index 8126dbd..bcc00e2 100644 (file)
@@ -1,4 +1,5 @@
 /*
+**
 **  PCI Lower Bus Adapter (LBA) manager
 **
 **     (c) Copyright 1999,2000 Grant Grundler
 ** bus number for each LBA depending on what firmware does.
 */
 
-#define MODULE_NAME "lba"
+#define MODULE_NAME "LBA"
 
 #define LBA_FUNC_ID    0x0000  /* function id */
 #define LBA_FCLASS     0x0008  /* function class, bist, header, rev... */
 #define LBA_EIOS_BASE  0x0260  /* Extra I/O port space */
 #define LBA_EIOS_MASK  0x0268
 
+#define LBA_GLOBAL_MASK        0x0270  /* Mercury only: Global Address Mask */
 #define LBA_DMA_CTL    0x0278  /* firmware sets this */
 
 #define LBA_IBASE      0x0300  /* SBA DMA support */
 #define LBA_IOSAPIC_BASE       0x800 /* Offset of IRQ logic */
 
 /* non-postable I/O port space, densely packed */
-#ifdef CONFIG_PARISC64
-#define LBA_ASTRO_PORT_BASE    (0xfffffffffee00000UL)
-#else
-#define LBA_ASTRO_PORT_BASE    (0xfee00000UL)
-#endif
+#define LBA_PORT_BASE  (PCI_F_EXTEND | 0xfee00000UL)
 
 #define ELROY_HVERS    0x782
 #define MERCURY_HVERS  0x783
@@ -283,8 +281,8 @@ static u32 lba_t32;
 ** Extract LBA (Rope) number from HPA
 ** REVISIT: 16 ropes for Stretch/Ike?
 */
-#define ROPES_PER_SBA  8
-#define LBA_NUM(x)    ((((unsigned long) x) >> 13) & (ROPES_PER_SBA-1))
+#define ROPES_PER_IOC  8
+#define LBA_NUM(x)    ((((unsigned long) x) >> 13) & (ROPES_PER_IOC-1))
 
 
 static void
@@ -444,7 +442,8 @@ lba_device_present( u8 bus, u8 dfn, struct lba_device *d)
 }
 
 #define LBA_CFG_TR4_ADDR_SETUP(d, addr) \
-    WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR)
+    WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); \
+    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR)
 
 #define LBA_CFG_ADDR_SETUP(d, addr) {                          \
     WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); \
@@ -520,7 +519,16 @@ lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size)
        return(data);
 }
 
-#ifdef CONFIG_PARISC64
+
+#if USE_PAT_PDC_CFG
+
+/* PAT PDC needs to be relocated in order to perform properly.
+ * tg3 driver does about 1600 PCI Cfg writes to initialize the card.
+ * On 440Mhz A500, PDC takes ~20ms/write, or ~30 seconds per card.
+ * On PA8800, that takes about 5ms/write (8 seconds).
+ * But relocating PDC will burn at least 4MB of RAM.
+ * Easier/Cheaper to just maintain our own mercury cfg ops.
+ */
 #define pat_cfg_addr(bus, devfn, addr) (((bus) << 16) | ((devfn) << 8) | (addr))
 
 static int pat_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
@@ -553,11 +561,84 @@ static struct pci_ops pat_cfg_ops = {
        .read =         pat_cfg_read,
        .write =        pat_cfg_write,
 };
-#else
-/* keep the compiler from complaining about undeclared variables */
-#define pat_cfg_ops lba_cfg_ops
 #endif
 
+
+#ifdef CONFIG_PARISC64
+static int mercury_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
+{
+       struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
+       u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+       u32 tok = LBA_CFG_TOK(local_bus, devfn);
+
+       /* Basic Algorithm
+       ** Should only get here on fully working LBA rev.
+       ** This is how simple the original LBA code should have been.
+       */
+       LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
+       switch(size) {
+       case 1: *(u8 *)  data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA
+                                                       + (pos & 3));
+               DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos,
+                               *(u8 *)data);
+               return(*(u8 *)data == (u8) ~0U);
+       case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA
+                                                       + (pos & 2));
+               DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos,
+                               *(u16 *)data);
+               return(*(u16 *)data == (u16) ~0U);
+       case 4: *(u32 *) data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA);
+               DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos, *data);
+               return(*data == ~0U);
+       }
+       DBG_CFG("%s(%x+%2x) -> bad size (%d)\n", __FUNCTION__, tok, pos, size);
+       *data = ~0U;
+       return(!PCIBIOS_SUCCESSFUL);    /* failed */
+}
+
+/*
+ * LBA 4.0 config write code implements non-postable semantics
+ * by doing a read of CONFIG ADDR after the write.
+ */
+
+static int mercury_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data)
+{
+       struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
+       unsigned long data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA;
+       u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
+       u32 tok = LBA_CFG_TOK(local_bus,devfn);
+
+       ASSERT((tok & 0xff) == 0);
+       ASSERT(pos < 0x100);
+
+       DBG_CFG("%s(%x+%2x) <- 0x%x (c)\n", __FUNCTION__, tok, pos, data);
+
+       /* Basic Algorithm */
+       LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
+       switch(size) {
+       case 1:         WRITE_REG8 (data, data_reg + (pos & 3)); break;
+       case 2:         WRITE_REG16(data, data_reg + (pos & 2)); break;
+       case 4:         WRITE_REG32(data, data_reg);             break;
+       default: 
+               DBG_CFG("%s(%x+%2x) WTF! size %d\n", __FUNCTION__, tok, pos,
+                               size);
+       }
+
+       /* flush posted write */
+       lba_t32 = READ_U32(d->hba.base_addr + LBA_PCI_CFG_ADDR);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+static struct pci_ops mercury_cfg_ops = {
+       .read =         mercury_cfg_read,
+       .write =        mercury_cfg_write,
+};
+#else
+#define mercury_cfg_ops lba_cfg_ops
+#endif /* CONFIG_PARISC64 */
+
+
 static int lba_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
 {
        struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
@@ -768,7 +849,7 @@ lba_fixup_bus(struct pci_bus *bus)
                pci_read_bridge_bases(bus);
        } else {
                /* Host-PCI Bridge */
-               int err;
+               int err, i;
 
                DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
                        ldev->hba.io_space.name,
@@ -781,30 +862,65 @@ lba_fixup_bus(struct pci_bus *bus)
 
                err = request_resource(&ioport_resource, &(ldev->hba.io_space));
                if (err < 0) {
-                       BUG();
                        lba_dump_res(&ioport_resource, 2);
+                       BUG();
+               }
+
+               if (ldev->hba.elmmio_space.start) {
+                       err = request_resource(&iomem_resource,
+                                       &(ldev->hba.elmmio_space));
+                       if (err < 0) {
+
+                               printk("FAILED: lba_fixup_bus() request for "
+                                               "elmmio_space [%lx/%lx]\n",
+                                               ldev->hba.elmmio_space.start,
+                                               ldev->hba.elmmio_space.end);
+
+                               /* lba_dump_res(&iomem_resource, 2); */
+                               /* BUG(); */
+                       }
                }
 
                err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
                if (err < 0) {
-                       BUG();
-                       lba_dump_res(&iomem_resource, 2);
+                       /*   FIXME  overlaps with elmmio will fail here.
+                        *   Need to prune (or disable) the distributed range.
+                        *
+                        *   BEWARE: conflicts with this lmmio range may be
+                        *   elmmio range which is pointing down another rope.
+                        */
+
+                       printk("FAILED: lba_fixup_bus() request for "
+                                       "lmmio_space [%lx/%lx]\n",
+                                       ldev->hba.lmmio_space.start,
+                                       ldev->hba.lmmio_space.end);
+                       /* lba_dump_res(&iomem_resource, 2); */
                }
 
 #ifdef CONFIG_PARISC64
+               /* GMMIO is  distributed range. Every LBA/Rope gets part it. */
                if (ldev->hba.gmmio_space.flags) {
                        err = request_resource(&iomem_resource, &(ldev->hba.gmmio_space));
                        if (err < 0) {
-                               BUG();
+                               printk("FAILED: lba_fixup_bus() request for "
+                                       "gmmio_space [%lx/%lx]\n",
+                                       ldev->hba.gmmio_space.start,
+                                       ldev->hba.gmmio_space.end);
                                lba_dump_res(&iomem_resource, 2);
+                               BUG();
                        }
-                       bus->resource[2] = &(ldev->hba.gmmio_space);
                }
 #endif
 
                /* advertize Host bridge resources to PCI bus */
                bus->resource[0] = &(ldev->hba.io_space);
                bus->resource[1] = &(ldev->hba.lmmio_space);
+               i=2;
+               if (ldev->hba.elmmio_space.start)
+                       bus->resource[i++] = &(ldev->hba.elmmio_space);
+               if (ldev->hba.gmmio_space.start)
+                       bus->resource[i++] = &(ldev->hba.gmmio_space);
+                       
        }
 
        list_for_each(ln, &bus->devices) {
@@ -837,6 +953,9 @@ lba_fixup_bus(struct pci_bus *bus)
                                res->start = PCI_HOST_ADDR(HBA_DATA(ldev), res->start);
                                res->end   = PCI_HOST_ADDR(HBA_DATA(ldev), res->end);
                                DBG("[%lx/%lx]\n", res->start, res->end);
+                       } else {
+                               DBG("lba_fixup_bus() WTF? 0x%lx [%lx/%lx] XXX",
+                                       res->flags, res->start, res->end);
                        }
                }
 
@@ -918,7 +1037,7 @@ struct pci_bios_ops lba_bios_ops = {
 static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \
 { \
        u##size t; \
-       t = READ_REG##size(LBA_ASTRO_PORT_BASE + addr); \
+       t = READ_REG##size(LBA_PORT_BASE + addr); \
        DBG_PORT(" 0x%x\n", t); \
        return (t); \
 }
@@ -960,7 +1079,7 @@ static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val)
 { \
        ASSERT(d != NULL); \
        DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
-       WRITE_REG##size(val, LBA_ASTRO_PORT_BASE + addr); \
+       WRITE_REG##size(val, LBA_PORT_BASE + addr); \
        if (LBA_DEV(d)->hw_rev < 3) \
                lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \
 }
@@ -1001,7 +1120,6 @@ static struct pci_port_ops lba_astro_port_ops = {
 static u##size lba_pat_in##size (struct pci_hba_data *l, u16 addr) \
 { \
        u##size t; \
-       ASSERT(bus != NULL); \
        DBG_PORT("%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \
        t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \
        DBG_PORT(" 0x%x\n", t); \
@@ -1018,7 +1136,6 @@ LBA_PORT_IN(32, 0)
 static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \
 { \
        void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \
-       ASSERT(bus != NULL); \
        DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
        WRITE_REG##size(val, where); \
        /* flush the I/O down to the elroy at least */ \
@@ -1099,10 +1216,23 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 
                case PAT_LMMIO:
                        /* used to fix up pre-initialized MEM BARs */
-                       lba_dev->hba.lmmio_space_offset = p->start - io->start;
+                       if (!lba_dev->hba.lmmio_space.start) {
+                               sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO",
+                                       (int) lba_dev->hba.bus_num.start);
+                               lba_dev->hba.lmmio_space_offset = p->start - io->start;
+                               r = &(lba_dev->hba.lmmio_space);
+                               r->name  = lba_dev->hba.lmmio_name;
+                       } else if (!lba_dev->hba.elmmio_space.start) {
+                               sprintf(lba_dev->hba.elmmio_name, "PCI%02x ELMMIO",
+                                       (int) lba_dev->hba.bus_num.start);
+                               r = &(lba_dev->hba.elmmio_space);
+                               r->name  = lba_dev->hba.elmmio_name;
+                       } else {
+                               printk(KERN_WARNING MODULE_NAME
+                                       " only supports 2 LMMIO resources!\n");
+                               break;
+                       }
 
-                       r = &(lba_dev->hba.lmmio_space);
-                       r->name   = "LBA LMMIO";
                        r->start  = p->start;
                        r->end    = p->end;
                        r->flags  = IORESOURCE_MEM;
@@ -1111,8 +1241,10 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 
                case PAT_GMMIO:
                        /* MMIO space > 4GB phys addr; for 64-bit BAR */
+                       sprintf(lba_dev->hba.gmmio_name, "PCI%02x GMMIO",
+                                       (int) lba_dev->hba.bus_num.start);
                        r = &(lba_dev->hba.gmmio_space);
-                       r->name   = "LBA GMMIO";
+                       r->name  = lba_dev->hba.gmmio_name;
                        r->start  = p->start;
                        r->end    = p->end;
                        r->flags  = IORESOURCE_MEM;
@@ -1132,8 +1264,10 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
                        */
                        lba_dev->iop_base = p->start;
 
+                       sprintf(lba_dev->hba.io_name, "PCI%02x Ports",
+                                       (int) lba_dev->hba.bus_num.start);
                        r = &(lba_dev->hba.io_space);
-                       r->name   = "LBA I/O Port";
+                       r->name  = lba_dev->hba.io_name;
                        r->start  = HBA_PORT_BASE(lba_dev->hba.hba_num);
                        r->end    = r->start + HBA_PORT_SPACE_SIZE - 1;
                        r->flags  = IORESOURCE_IO;
@@ -1155,24 +1289,17 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 #endif /* CONFIG_PARISC64 */
 
 
+extern void sba_distributed_lmmio(struct parisc_device *, struct resource *);
+extern void sba_directed_lmmio(struct parisc_device *, struct resource *);
+
+
 static void
 lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 {
        struct resource *r;
-       unsigned long rsize;
        int lba_num;
 
-#ifdef CONFIG_PARISC64
-       /*
-       ** Sign extend all BAR values on "legacy" platforms.
-       ** "Sprockets" PDC (Forte/Allegro) initializes everything
-       ** for "legacy" 32-bit OS (HPUX 10.20).
-       ** Upper 32-bits of 64-bit BAR will be zero too.
-       */
-       lba_dev->hba.lmmio_space_offset = 0xffffffff00000000UL;
-#else
-       lba_dev->hba.lmmio_space_offset = 0UL;
-#endif
+       lba_dev->hba.lmmio_space_offset = PCI_F_EXTEND;
 
        /*
        ** With "legacy" firmware, the lowest byte of FW_SCRATCH
@@ -1187,27 +1314,104 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
        r->start = lba_num & 0xff;
        r->end = (lba_num>>8) & 0xff;
 
-       /* Set up local PCI Bus resources - we don't really need
-       ** them for Legacy boxes but it's nice to see in /proc.
+       /* Set up local PCI Bus resources - we don't need them for
+       ** Legacy boxes but it's nice to see in /proc/iomem.
        */
        r = &(lba_dev->hba.lmmio_space);
-       r->name  = "LBA PCI LMMIO";
-       r->flags = IORESOURCE_MEM;
-       /* Ignore "Range Enable" bit in the BASE register */
-       r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev),
-               ((long) READ_REG32(pa_dev->hpa + LBA_LMMIO_BASE)) & ~1UL);
-       rsize =  ~READ_REG32(pa_dev->hpa + LBA_LMMIO_MASK) + 1;
-
+       sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO",
+                                       (int) lba_dev->hba.bus_num.start);
+       r->name  = lba_dev->hba.lmmio_name;
+
+#if 1
+       /* We want the CPU -> IO routing of addresses.
+        * The SBA BASE/MASK registers control CPU -> IO routing.
+        * Ask SBA what is routed to this rope/LBA.
+        */
+       sba_distributed_lmmio(pa_dev, r);
+#else
        /*
-       ** Each rope only gets part of the distributed range.
-       ** Adjust "window" for this rope
-       */
-       rsize /= ROPES_PER_SBA;
-       r->start += rsize * LBA_NUM(pa_dev->hpa);
-       r->end = r->start + rsize - 1 ;
+        * The LBA BASE/MASK registers control IO -> System routing.
+        *
+        * The following code works but doesn't get us what we want.
+        * Well, only because firmware (v5.0) on C3000 doesn't program
+        * the LBA BASE/MASE registers to be the exact inverse of 
+        * the corresponding SBA registers. Other Astro/Pluto
+        * based platform firmware may do it right.
+        *
+        * Should someone want to mess with MSI, they may need to
+        * reprogram LBA BASE/MASK registers. Thus preserve the code
+        * below until MSI is known to work on C3000/A500/N4000/RP3440.
+        *
+        * Using the code below, /proc/iomem shows:
+        * ...
+        * f0000000-f0ffffff : PCI00 LMMIO
+        *   f05d0000-f05d0000 : lcd_data
+        *   f05d0008-f05d0008 : lcd_cmd
+        * f1000000-f1ffffff : PCI01 LMMIO
+        * f4000000-f4ffffff : PCI02 LMMIO
+        *   f4000000-f4001fff : sym53c8xx
+        *   f4002000-f4003fff : sym53c8xx
+        *   f4004000-f40043ff : sym53c8xx
+        *   f4005000-f40053ff : sym53c8xx
+        *   f4007000-f4007fff : ohci_hcd
+        *   f4008000-f40083ff : tulip
+        * f6000000-f6ffffff : PCI03 LMMIO
+        * f8000000-fbffffff : PCI00 ELMMIO
+        *   fa100000-fa4fffff : stifb mmio
+        *   fb000000-fb1fffff : stifb fb
+        *
+        * But everything listed under PCI02 actually lives under PCI00.
+        * This is clearly wrong.
+        *
+        * Asking SBA how things are routed tells the correct story:
+        * LMMIO_BASE/MASK/ROUTE f4000001 fc000000 00000000
+        * DIR0_BASE/MASK/ROUTE fa000001 fe000000 00000006
+        * DIR1_BASE/MASK/ROUTE f9000001 ff000000 00000004
+        * DIR2_BASE/MASK/ROUTE f0000000 fc000000 00000000
+        * DIR3_BASE/MASK/ROUTE f0000000 fc000000 00000000
+        *
+        * Which looks like this in /proc/iomem:
+        * f4000000-f47fffff : PCI00 LMMIO
+        *   f4000000-f4001fff : sym53c8xx
+        *   ...[deteled core devices - same as above]...
+        *   f4008000-f40083ff : tulip
+        * f4800000-f4ffffff : PCI01 LMMIO
+        * f6000000-f67fffff : PCI02 LMMIO
+        * f7000000-f77fffff : PCI03 LMMIO
+        * f9000000-f9ffffff : PCI02 ELMMIO
+        * fa000000-fbffffff : PCI03 ELMMIO
+        *   fa100000-fa4fffff : stifb mmio
+        *   fb000000-fb1fffff : stifb fb
+        *
+        * ie all Built-in core are under now correctly under PCI00.
+        * The "PCI02 ELMMIO" directed range is for:
+        *  +-[02]---03.0  3Dfx Interactive, Inc. Voodoo 2
+        *
+        * All is well now.
+        */
+       r->start = (long) READ_REG32(pa_dev->hpa + LBA_LMMIO_BASE);
+       if (r->start & 1) {
+               unsigned long rsize;
+
+               r->flags = IORESOURCE_MEM;
+               /* mmio_mask also clears Enable bit */
+               r->start &= mmio_mask;
+               r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev), r->start);
+               rsize = ~ READ_REG32(pa_dev->hpa + LBA_LMMIO_MASK);
+
+               /*
+               ** Each rope only gets part of the distributed range.
+               ** Adjust "window" for this rope.
+               */
+               rsize /= ROPES_PER_IOC;
+               r->start += (rsize + 1) * LBA_NUM(pa_dev->hpa);
+               r->end = r->start + rsize;
+       } else {
+               r->end = r->start = 0;  /* Not enabled. */
+       }
+#endif
 
        /*
-       ** XXX FIXME - ignore LBA_ELMMIO_BASE for now
        ** "Directed" ranges are used when the "distributed range" isn't
        ** sufficient for all devices below a given LBA.  Typically devices
        ** like graphics cards or X25 may need a directed range when the
@@ -1216,35 +1420,38 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
        **
        ** The main reason for ignoring it now frigging complications.
        ** Directed ranges may overlap (and have precedence) over
-       ** distributed ranges. Ie a distributed range assigned to a unused
+       ** distributed ranges. Or a distributed range assigned to a unused
        ** rope may be used by a directed range on a different rope.
        ** Support for graphics devices may require fixing this
        ** since they may be assigned a directed range which overlaps
        ** an existing (but unused portion of) distributed range.
        */
        r = &(lba_dev->hba.elmmio_space);
-       r->name  = "extra LBA PCI LMMIO";
-       r->flags = IORESOURCE_MEM;
+       sprintf(lba_dev->hba.elmmio_name, "PCI%02x ELMMIO",
+                                       (int) lba_dev->hba.bus_num.start);
+       r->name  = lba_dev->hba.elmmio_name;
+
+#if 1
+       /* See comment which precedes call to sba_directed_lmmio() */
+       sba_directed_lmmio(pa_dev, r);
+#else
        r->start = READ_REG32(pa_dev->hpa + LBA_ELMMIO_BASE);
-       r->end   = 0;
 
-       /* check Range Enable bit */
        if (r->start & 1) {
-               /* First baby step to getting Direct Ranges listed in /proc.
-               ** AFAIK, only Sprockets PDC will setup a directed Range.
-               */
-
-               r->start &= ~1;
-               r->end    = r->start;
-               r->end   += ~READ_REG32(pa_dev->hpa + LBA_ELMMIO_MASK);
-               printk(KERN_DEBUG "WARNING: Ignoring enabled ELMMIO BASE 0x%0lx  SIZE 0x%lx\n",
-                       r->start,
-                       r->end + 1);
-
+               unsigned long rsize;
+               r->flags = IORESOURCE_MEM;
+               /* mmio_mask also clears Enable bit */
+               r->start &= mmio_mask;
+               r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev), r->start);
+               rsize = READ_REG32(pa_dev->hpa + LBA_ELMMIO_MASK);
+               r->end = r->start + ~rsize;
        }
+#endif
 
        r = &(lba_dev->hba.io_space);
-       r->name  = "LBA PCI I/O Ports";
+       sprintf(lba_dev->hba.io_name, "PCI%02x Ports",
+                                       (int) lba_dev->hba.bus_num.start);
+       r->name  = lba_dev->hba.io_name;
        r->flags = IORESOURCE_IO;
        r->start = READ_REG32(pa_dev->hpa + LBA_IOS_BASE) & ~1L;
        r->end   = r->start + (READ_REG32(pa_dev->hpa + LBA_IOS_MASK) ^ (HBA_PORT_SPACE_SIZE - 1));
@@ -1478,11 +1685,16 @@ lba_driver_probe(struct parisc_device *dev)
        dev->dev.platform_data = lba_dev;
        lba_bus = lba_dev->hba.hba_bus =
                pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
-                               is_pdc_pat() ? &pat_cfg_ops : &lba_cfg_ops,
+                               IS_ELROY(dev) ? &lba_cfg_ops : &mercury_cfg_ops,
                                NULL);
 
+       /* This is in lieu of calling pci_assign_unassigned_resources() */
        if (is_pdc_pat()) {
                /* assign resources to un-initialized devices */
+
+               DBG_PAT("LBA pci_bus_size_bridges()\n");
+               pci_bus_size_bridges(lba_bus);
+
                DBG_PAT("LBA pci_bus_assign_resources()\n");
                pci_bus_assign_resources(lba_bus);
 
@@ -1493,6 +1705,8 @@ lba_driver_probe(struct parisc_device *dev)
                lba_dump_res(&lba_dev->hba.lmmio_space, 2);
 #endif
        }
+       pci_enable_bridges(lba_bus);
+
 
        /*
        ** Once PCI register ops has walked the bus, access to config
index 9a2a26c..d097e7e 100644 (file)
@@ -54,9 +54,9 @@
 
 
 #ifdef DEBUG
-# define DPRINTK(x) printk x
+# define DPRINTK(x...) printk(x)
 #else
-# define DPRINTK(x) do { } while (0)
+# define DPRINTK(x...)
 #endif
 
 
@@ -120,14 +120,14 @@ static int shutdown_timer;
 static void process_shutdown(void)
 {
        if (shutdown_timer == 0)
-               DPRINTK((KERN_INFO "Shutdown requested...\n"));
+               DPRINTK(KERN_INFO "Shutdown requested...\n");
 
        shutdown_timer++;
        
        /* wait until the button was pressed for 1 second */
        if (shutdown_timer == HZ) {
                static char msg[] = "Shutting down...";
-               DPRINTK((KERN_INFO "%s\n", msg));
+               DPRINTK(KERN_INFO "%s\n", msg);
 #ifdef CONFIG_CHASSIS_LCD_LED
                lcd_print(msg);
 #endif
index f3cf291..609d5f4 100644 (file)
@@ -1,8 +1,9 @@
 /*
 **  System Bus Adapter (SBA) I/O MMU manager
 **
-**     (c) Copyright 2000 Grant Grundler
-**     (c) Copyright 2000 Hewlett-Packard Company
+**     (c) Copyright 2000-2004 Grant Grundler <grundler @ parisc-linux x org>
+**     (c) Copyright 2004 Naresh Kumar Inna <knaresh at india x hp x com>
+**     (c) Copyright 2000-2004 Hewlett-Packard Company
 **
 **     Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code)
 **
@@ -167,11 +168,21 @@ extern struct proc_dir_entry * proc_mckinley_root;
 
 #define MAX_IOC                2       /* per Ike. Pluto/Astro only have 1. */
 
+#define ROPES_PER_IOC  8       /* per Ike half or Pluto/Astro */
+
 
 /*
 ** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
 ** Firmware programs this stuff. Don't touch it.
 */
+#define LMMIO_DIRECT0_BASE  0x300
+#define LMMIO_DIRECT0_MASK  0x308
+#define LMMIO_DIRECT0_ROUTE 0x310
+
+#define LMMIO_DIST_BASE  0x360
+#define LMMIO_DIST_MASK  0x368
+#define LMMIO_DIST_ROUTE 0x370
+
 #define IOS_DIST_BASE  0x390
 #define IOS_DIST_MASK  0x398
 #define IOS_DIST_ROUTE 0x3A0
@@ -289,6 +300,9 @@ struct sba_device {
        unsigned int            flags;  /* state/functionality enabled */
        unsigned int            hw_rev;  /* HW revision of chip */
 
+       struct resource         chip_resv; /* MMIO reserved for chip */
+       struct resource         iommu_resv; /* MMIO reserved for iommu */
+
        unsigned int            num_ioc;  /* number of on-board IOC's */
        struct ioc              ioc[MAX_IOC];
 };
@@ -569,7 +583,7 @@ sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted)
                while(res_ptr < res_end)
                { 
                        DBG_RES("    %p %lx %lx\n", res_ptr, mask, *res_ptr);
-                       ASSERT(0 != mask);
+                       BUG_ON(0 == mask);
                        if(0 == ((*res_ptr) & mask)) {
                                *res_ptr |= mask;     /* mark resources busy! */
                                pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
@@ -1696,19 +1710,46 @@ sba_hw_init(struct sba_device *sba_dev)
        } /* if !PLUTO */
 
        if (IS_ASTRO(sba_dev->iodc)) {
+               int err;
                /* PAT_PDC (L-class) also reports the same goofy base */
                sba_dev->ioc[0].ioc_hpa = ASTRO_IOC_OFFSET;
                num_ioc = 1;
+
+               sba_dev->chip_resv.name = "Astro Intr Ack";
+               sba_dev->chip_resv.start = PCI_F_EXTEND | 0xfef00000UL;
+               sba_dev->chip_resv.end   = PCI_F_EXTEND | (0xff000000UL - 1) ;
+               err = request_resource(&iomem_resource, &(sba_dev->chip_resv));
+               if (err < 0) {
+                       BUG();
+               }
+
        } else if (IS_PLUTO(sba_dev->iodc)) {
+               int err;
+
                /* We use a negative value for IOC HPA so it gets 
                  * corrected when we add it with IKE's IOC offset.
                 * Doesnt look clean, but fewer code. 
                  */
                sba_dev->ioc[0].ioc_hpa = -PLUTO_IOC_OFFSET;
                num_ioc = 1;
+
+               sba_dev->chip_resv.name = "Pluto Intr/PIOP/VGA";
+               sba_dev->chip_resv.start = PCI_F_EXTEND | 0xfee00000UL;
+               sba_dev->chip_resv.end   = PCI_F_EXTEND | (0xff200000UL - 1);
+               err = request_resource(&iomem_resource, &(sba_dev->chip_resv));
+               BUG_ON(err < 0);
+
+               sba_dev->iommu_resv.name = "IOVA Space";
+               sba_dev->iommu_resv.start = 0x40000000UL;
+               sba_dev->iommu_resv.end   = 0x50000000UL - 1;
+               err = request_resource(&iomem_resource, &(sba_dev->iommu_resv));
+               BUG_ON(err < 0);
        } else {
+               /* IS_IKE (ie N-class, L3000, L1500) */
                sba_dev->ioc[0].ioc_hpa = sba_dev->ioc[1].ioc_hpa = 0;
                num_ioc = 2;
+
+               /* TODO - LOOKUP Ike/Stretch chipset mem map */
        }
 
        sba_dev->num_ioc = num_ioc;
@@ -1843,8 +1884,9 @@ static int sba_proc_info(char *buf, char **start, off_t offset, int len)
        struct sba_device *sba_dev = sba_list;
        struct ioc *ioc = &sba_dev->ioc[0];     /* FIXME: Multi-IOC support! */
        int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
+       unsigned long i;
 #ifdef SBA_COLLECT_STATS
-       unsigned long i = 0, avg = 0, min, max;
+       unsigned long avg = 0, min, max;
 #endif
 
        sprintf(buf, "%s rev %d.%d\n",
@@ -1860,6 +1902,21 @@ static int sba_proc_info(char *buf, char **start, off_t offset, int len)
        sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", 
                buf, ioc->res_size, ioc->res_size << 3);   /* 8 bits per byte */
 
+       sprintf(buf, "%sLMMIO_BASE/MASK/ROUTE %08x %08x %08x\n",
+               buf,
+               READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_BASE),
+               READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_MASK),
+               READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_ROUTE)
+               );
+
+       for (i=0; i<4; i++)
+               sprintf(buf, "%sDIR%ld_BASE/MASK/ROUTE %08x %08x %08x\n",
+                       buf, i,
+                       READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_BASE  + i*0x18),
+                       READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_MASK  + i*0x18),
+                       READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_ROUTE + i*0x18)
+               );
+
 #ifdef SBA_COLLECT_STATS
        sprintf(buf, "%sIO PDIR entries : %ld free  %ld used (%d%%)\n", buf,
                total_pages - ioc->used_pages, ioc->used_pages,
@@ -1949,7 +2006,7 @@ static struct parisc_driver sba_driver = {
 };
 
 /*
-** Determine if lba should claim this chip (return 0) or not (return 1).
+** Determine if sba should claim this chip (return 0) or not (return 1).
 ** If so, initialize the chip and tell other partners in crime they
 ** have work to do.
 */
@@ -2062,17 +2119,95 @@ void __init sba_init(void)
  * sba_get_iommu - Assign the iommu pointer for the pci bus controller.
  * @dev: The parisc device.
  *
- * This function searches through the registerd IOMMU's and returns the
- * appropriate IOMMU data for the given parisc PCI controller.
+ * Returns the appropriate IOMMU data for the given parisc PCI controller.
+ * This is cached and used later for PCI DMA Mapping.
  */
 void * sba_get_iommu(struct parisc_device *pci_hba)
 {
-       struct sba_device *sba = (struct sba_device *) pci_hba->parent->sysdata;
-       char t = pci_hba->parent->id.hw_type;
+       struct parisc_device *sba_dev = parisc_parent(pci_hba);
+       struct sba_device *sba = sba_dev->dev.driver_data;
+       char t = sba_dev->id.hw_type;
        int iocnum = (pci_hba->hw_path >> 3);   /* rope # */
 
+       BUG_ON((t != HPHW_IOA) && (t != HPHW_BCPORT));
+
+       return &(sba->ioc[iocnum]);
+}
+
+
+/**
+ * sba_directed_lmmio - return first directed LMMIO range routed to rope
+ * @pa_dev: The parisc device.
+ * @r: resource PCI host controller wants start/end fields assigned.
+ *
+ * For the given parisc PCI controller, determine if any direct ranges
+ * are routed down the corresponding rope.
+ */
+void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r)
+{
+       struct parisc_device *sba_dev = parisc_parent(pci_hba);
+       struct sba_device *sba = sba_dev->dev.driver_data;
+       char t = sba_dev->id.hw_type;
+       int i;
+       int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1));  /* rope # */
+
        if ((t!=HPHW_IOA) && (t!=HPHW_BCPORT))
                BUG();
 
-       return &(sba->ioc[iocnum]);
+       r->start = r->end = 0;
+
+       /* Astro has 4 directed ranges. Not sure about Ike/Pluto/et al */
+       for (i=0; i<4; i++) {
+               int base, size;
+               unsigned long reg = sba->sba_hpa + i*0x18;
+
+               base = READ_REG32(reg + LMMIO_DIRECT0_BASE);
+               if ((base & 1) == 0)
+                       continue;       /* not enabled */
+
+               size = READ_REG32(reg + LMMIO_DIRECT0_ROUTE);
+
+               if ((size & (ROPES_PER_IOC-1)) != rope)
+                       continue;       /* directed down different rope */
+               
+               r->start = (base & ~1UL) | PCI_F_EXTEND;
+               size = ~ READ_REG32(reg + LMMIO_DIRECT0_MASK);
+               r->end = r->start + size;
+       }
+}
+
+
+/**
+ * sba_distributed_lmmio - return portion of distributed LMMIO range
+ * @pa_dev: The parisc device.
+ * @r: resource PCI host controller wants start/end fields assigned.
+ *
+ * For the given parisc PCI controller, return portion of distributed LMMIO
+ * range. The distributed LMMIO is always present and it's just a question
+ * of the base address and size of the range.
+ */
+void sba_distributed_lmmio(struct parisc_device *pci_hba, struct resource *r )
+{
+       struct parisc_device *sba_dev = parisc_parent(pci_hba);
+       struct sba_device *sba = sba_dev->dev.driver_data;
+       char t = sba_dev->id.hw_type;
+       int base, size;
+       int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1));  /* rope # */
+
+       if ((t!=HPHW_IOA) && (t!=HPHW_BCPORT))
+               BUG();
+
+       r->start = r->end = 0;
+
+       base = READ_REG32(sba->sba_hpa + LMMIO_DIST_BASE);
+       if ((base & 1) == 0) {
+               BUG();  /* Gah! Distr Range wasn't enabled! */
+               return;
+       }
+
+       r->start = (base & ~1UL) | PCI_F_EXTEND;
+
+       size = (~READ_REG32(sba->sba_hpa + LMMIO_DIST_MASK)) / ROPES_PER_IOC;
+       r->start += rope * (size + 1);  /* adjust base for this rope */
+       r->end = r->start + size;
 }
index 156e46a..db8fe4c 100644 (file)
@@ -34,7 +34,7 @@ config PARPORT
 
 config PARPORT_PC
        tristate "PC-style hardware"
-       depends on PARPORT && (!SPARC64 || PCI)
+       depends on PARPORT && (!SPARC64 || PCI) && (!SPARC32 || BROKEN)
        ---help---
          You should say Y here if you have a PC-style parallel port. All
          IBM PC compatible computers and some Alphas have PC-style
index c7a7e06..13b9b60 100644 (file)
@@ -52,7 +52,7 @@ static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_reg
 
 static void parport_sunbpp_disable_irq(struct parport *p)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
        u32 tmp;
 
        tmp = sbus_readl(&regs->p_csr);
@@ -62,7 +62,7 @@ static void parport_sunbpp_disable_irq(struct parport *p)
 
 static void parport_sunbpp_enable_irq(struct parport *p)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
        u32 tmp;
 
        tmp = sbus_readl(&regs->p_csr);
@@ -72,7 +72,7 @@ static void parport_sunbpp_enable_irq(struct parport *p)
 
 static void parport_sunbpp_write_data(struct parport *p, unsigned char d)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
 
        sbus_writeb(d, &regs->p_dr);
        dprintk((KERN_DEBUG "wrote 0x%x\n", d));
@@ -80,7 +80,7 @@ static void parport_sunbpp_write_data(struct parport *p, unsigned char d)
 
 static unsigned char parport_sunbpp_read_data(struct parport *p)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
 
        return sbus_readb(&regs->p_dr);
 }
@@ -88,7 +88,7 @@ static unsigned char parport_sunbpp_read_data(struct parport *p)
 #if 0
 static void control_pc_to_sunbpp(struct parport *p, unsigned char status)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
        unsigned char value_tcr = sbus_readb(&regs->p_tcr);
        unsigned char value_or = sbus_readb(&regs->p_or);
 
@@ -108,7 +108,7 @@ static void control_pc_to_sunbpp(struct parport *p, unsigned char status)
 
 static unsigned char status_sunbpp_to_pc(struct parport *p)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
        unsigned char bits = 0;
        unsigned char value_tcr = sbus_readb(&regs->p_tcr);
        unsigned char value_ir = sbus_readb(&regs->p_ir);
@@ -131,7 +131,7 @@ static unsigned char status_sunbpp_to_pc(struct parport *p)
 
 static unsigned char control_sunbpp_to_pc(struct parport *p)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
        unsigned char bits = 0;
        unsigned char value_tcr = sbus_readb(&regs->p_tcr);
        unsigned char value_or = sbus_readb(&regs->p_or);
@@ -159,7 +159,7 @@ static unsigned char parport_sunbpp_frob_control(struct parport *p,
                                                 unsigned char mask,
                                                 unsigned char val)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
        unsigned char value_tcr = sbus_readb(&regs->p_tcr);
        unsigned char value_or = sbus_readb(&regs->p_or);
 
@@ -216,7 +216,7 @@ static unsigned char parport_sunbpp_read_status(struct parport *p)
 
 static void parport_sunbpp_data_forward (struct parport *p)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
        unsigned char value_tcr = sbus_readb(&regs->p_tcr);
 
        dprintk((KERN_DEBUG "forward\n"));
@@ -226,7 +226,7 @@ static void parport_sunbpp_data_forward (struct parport *p)
 
 static void parport_sunbpp_data_reverse (struct parport *p)
 {
-       struct bpp_regs *regs = (struct bpp_regs *)p->base;
+       struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
        u8 val = sbus_readb(&regs->p_tcr);
 
        dprintk((KERN_DEBUG "reverse\n"));
@@ -299,9 +299,9 @@ static int __init init_one_port(struct sbus_dev *sdev)
        struct parport *p;
        /* at least in theory there may be a "we don't dma" case */
        struct parport_operations *ops;
-       unsigned long base;
+       void __iomem *base;
        int irq, dma, err = 0, size;
-       struct bpp_regs *regs;
+       struct bpp_regs __iomem *regs;
        unsigned char value_tcr;
        Node *node;
 
@@ -328,7 +328,7 @@ static int __init init_one_port(struct sbus_dev *sdev)
         memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
 
        dprintk(("register_port\n"));
-       if (!(p = parport_register_port(base, irq, dma, ops)))
+       if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
                goto out3;
 
        p->size = size;
@@ -343,7 +343,7 @@ static int __init init_one_port(struct sbus_dev *sdev)
        dprintk(("OK\n"));
        parport_sunbpp_enable_irq(p);
 
-       regs = (struct bpp_regs *)p->base;
+       regs = (struct bpp_regs __iomem *)p->base;
        dprintk((KERN_DEBUG "forward\n"));
        value_tcr = sbus_readb(&regs->p_tcr);
        value_tcr &= ~P_TCR_DIR;
@@ -395,7 +395,7 @@ static void __exit parport_sunbpp_exit(void)
                        parport_sunbpp_disable_irq(p);
                        free_irq(p->irq, p);
                }
-               sbus_iounmap(p->base, p->size);
+               sbus_iounmap((void __iomem *)p->base, p->size);
                parport_put_port(p);
                kfree (ops);
                list_del(&node->list);
index e94a854..dbd3360 100644 (file)
@@ -68,6 +68,25 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
        return ret;
 }
 
+/**
+ * add a single device
+ * @dev: device to add
+ *
+ * This adds a single pci device to the global
+ * device list and adds sysfs and procfs entries
+ */
+void __devinit pci_bus_add_device(struct pci_dev *dev)
+{
+       device_add(&dev->dev);
+
+       spin_lock(&pci_bus_lock);
+       list_add_tail(&dev->global_list, &pci_devices);
+       spin_unlock(&pci_bus_lock);
+
+       pci_proc_attach_device(dev);
+       pci_create_sysfs_dev_files(dev);
+}
+
 /**
  * pci_bus_add_devices - insert newly discovered PCI devices
  * @bus: bus to check for new devices
@@ -91,16 +110,7 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus)
                 */
                if (!list_empty(&dev->global_list))
                        continue;
-
-               device_add(&dev->dev);
-
-               spin_lock(&pci_bus_lock);
-               list_add_tail(&dev->global_list, &pci_devices);
-               spin_unlock(&pci_bus_lock);
-
-               pci_proc_attach_device(dev);
-               pci_create_sysfs_dev_files(dev);
-
+               pci_bus_add_device(dev);
        }
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -136,5 +146,6 @@ void pci_enable_bridges(struct pci_bus *bus)
 }
 
 EXPORT_SYMBOL(pci_bus_alloc_resource);
+EXPORT_SYMBOL_GPL(pci_bus_add_device);
 EXPORT_SYMBOL(pci_bus_add_devices);
 EXPORT_SYMBOL(pci_enable_bridges);
index 4fc3ed9..93c120d 100644 (file)
@@ -51,7 +51,6 @@ rpadlpar_io-objs      :=      rpadlpar_core.o \
 pciehp-objs            :=      pciehp_core.o   \
                                pciehp_ctrl.o   \
                                pciehp_pci.o    \
-                               pciehp_sysfs.o  \
                                pciehp_hpc.o
 ifdef CONFIG_ACPI_BUS
        pciehp-objs += pciehprm_acpi.o
index fe7866c..aced661 100644 (file)
@@ -64,6 +64,8 @@ do {                                                  \
 #define IBM_HARDWARE_ID1 "IBM37D0"
 #define IBM_HARDWARE_ID2 "IBM37D4"
 
+#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun)
+
 /* union apci_descriptor - allows access to the
  * various device descriptors that are embedded in the
  * aPCI table
@@ -84,6 +86,7 @@ union apci_descriptor {
                u8  attn;
                u8  status[2];
                u8  sun;
+               u8  res[3];
        } slot;
        struct {
                u8 type;
@@ -128,6 +131,43 @@ static struct acpiphp_attention_info ibm_attention_info =
        .owner = THIS_MODULE,
 };
 
+/**
+ * ibm_slot_from_id - workaround for bad ibm hardware
+ * @id: the slot number that linux refers to the slot by
+ *
+ * Description: this method returns the aCPI slot descriptor
+ * corresponding to the Linux slot number.  This descriptor
+ * has info about the aPCI slot id and attention status.
+ * This descriptor must be freed using kfree when done.
+ **/
+static union apci_descriptor *ibm_slot_from_id(int id)
+{
+       int ind = 0, size;
+       union apci_descriptor *ret = NULL, *des;
+       char *table;
+
+       size = ibm_get_table_from_acpi(&table);
+       des = (union apci_descriptor *)table;
+       if (memcmp(des->header.sig, "aPCI", 4) != 0)
+               goto ibm_slot_done;
+
+       des = (union apci_descriptor *)&table[ind += des->header.len];
+       while (ind < size && (des->generic.type != 0x82 ||
+                       des->slot.slot_num != id)) {
+               des = (union apci_descriptor *)&table[ind += des->generic.len];
+       }
+
+       if (ind < size && des->slot.slot_num == id)
+               ret = des;
+
+ibm_slot_done:
+       if (ret) {
+               ret = kmalloc(sizeof(union apci_descriptor), GFP_KERNEL);
+               memcpy(ret, des, sizeof(union apci_descriptor));
+       }
+       kfree(table);
+       return ret;
+}
 
 /**
  * ibm_set_attention_status - callback method to set the attention LED
@@ -139,32 +179,34 @@ static struct acpiphp_attention_info ibm_attention_info =
  **/
 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;
+       unsigned long rc;
+       union apci_descriptor *ibm_slot;
 
-       acpi_slot = ((struct slot *)(slot->private))->acpi_slot;
+       ibm_slot = ibm_slot_from_id(hpslot_to_sun(slot));
 
-       dbg("%s: set slot %d attention status to %d\n", __FUNCTION__,
-                       acpi_slot->sun, (status ? 1 : 0));
+       dbg("%s: set slot %d (%d) attention status to %d\n", __FUNCTION__,
+                       ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
+                       (status ? 1 : 0));
 
        args[0].type = ACPI_TYPE_INTEGER;
-       args[0].integer.value = acpi_slot->sun;
+       args[0].integer.value = ibm_slot->slot.slot_id;
        args[1].type = ACPI_TYPE_INTEGER;
        args[1].integer.value = (status) ? 1 : 0;
 
+       kfree(ibm_slot);
+
        stat = acpi_evaluate_integer(ibm_acpi_handle, "APLS", &params, &rc);
        if (ACPI_FAILURE(stat)) {
-               retval = -ENODEV;
                err("APLS evaluation failed:  0x%08x\n", stat);
+               return -ENODEV;
        } else if (!rc) {
-               retval = -ERANGE;
                err("APLS method failed:  0x%08lx\n", rc);
+               return -ERANGE;
        }
-       return retval;
+       return 0;
 }
 
 /**
@@ -181,38 +223,21 @@ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status)
  **/
 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;
+       union apci_descriptor *ibm_slot;
 
-       acpi_slot = ((struct slot *)(slot->private))->acpi_slot;
+       ibm_slot = ibm_slot_from_id(hpslot_to_sun(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;
-       }
+       if (ibm_slot->slot.attn & 0xa0 || ibm_slot->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);
+       dbg("%s: get slot %d (%d) attention status is %d\n", __FUNCTION__,
+                       ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
+                       *status);
 
-get_attn_done:
-       kfree(table);
-       return retval;
+       kfree(ibm_slot);
+       return 0;
 }
 
 /**
index 8cf4bd3..ac98a11 100644 (file)
@@ -92,7 +92,7 @@ static u8 evbuffer_init;
 static u8 evbuffer_length;
 static u8 evbuffer[1024];
 
-static void *compaq_int15_entry_point;
+static void __iomem *compaq_int15_entry_point;
 
 static spinlock_t int15_lock;          /* lock for ordering int15_bios_call() */
 
@@ -141,7 +141,7 @@ static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail)
  *
  * returns 0 for non-Compaq ROM, 1 for Compaq ROM
  */
-static int check_for_compaq_ROM (void *rom_start)
+static int check_for_compaq_ROM (void __iomem *rom_start)
 {
        u8 temp1, temp2, temp3, temp4, temp5, temp6;
        int result = 0;
@@ -197,7 +197,7 @@ static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
  *
  * Read the hot plug Resource Table from NVRAM
  */
-static int load_HRT (void *rom_start)
+static int load_HRT (void __iomem *rom_start)
 {
        u32 available;
        u32 temp_dword;
@@ -231,7 +231,7 @@ static int load_HRT (void *rom_start)
  *
  * Save the hot plug Resource Table in NVRAM
  */
-static u32 store_HRT (void *rom_start)
+static u32 store_HRT (void __iomem *rom_start)
 {
        u32 *buffer;
        u32 *pFill;
@@ -423,7 +423,7 @@ static u32 store_HRT (void *rom_start)
 }
 
 
-void compaq_nvram_init (void *rom_start)
+void compaq_nvram_init (void __iomem *rom_start)
 {
        if (rom_start) {
                compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);
@@ -435,7 +435,7 @@ void compaq_nvram_init (void *rom_start)
 }
 
 
-int compaq_nvram_load (void *rom_start, struct controller *ctrl)
+int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
 {
        u8 bus, device, function;
        u8 nummem, numpmem, numio, numbus;
@@ -648,7 +648,7 @@ int compaq_nvram_load (void *rom_start, struct controller *ctrl)
 }
 
        
-int compaq_nvram_store (void *rom_start)
+int compaq_nvram_store (void __iomem *rom_start)
 {
        int rc = 1;
 
index 9ed417b..e89c070 100644 (file)
 
 #ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM
 
-static inline void compaq_nvram_init (void *rom_start)
+static inline void compaq_nvram_init (void __iomem *rom_start)
 {
        return;
 }
 
-static inline int compaq_nvram_load (void *rom_start, struct controller *ctrl)
+static inline int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
 {
        return 0;
 }
 
-static inline int compaq_nvram_store (void *rom_start)
+static inline int compaq_nvram_store (void __iomem *rom_start)
 {
        return 0;
 }
 
 #else
 
-extern void compaq_nvram_init  (void *rom_start);
-extern int compaq_nvram_load   (void *rom_start, struct controller *ctrl);
-extern int compaq_nvram_store  (void *rom_start);
+extern void compaq_nvram_init  (void __iomem *rom_start);
+extern int compaq_nvram_load   (void __iomem *rom_start, struct controller *ctrl);
+extern int compaq_nvram_store  (void __iomem *rom_start);
 
 #endif
 
index 8453795..7cf086a 100644 (file)
@@ -165,14 +165,123 @@ static void remove_slot(struct dummy_slot *dslot)
                err("Problem unregistering a slot %s\n", dslot->slot->name);
 }
 
+/**
+ * Rescan slot.
+ * Tries hard not to re-enable already existing devices
+ * also handles scanning of subfunctions
+ *
+ * @param temp   Device template. Should be set: bus and devfn.
+ */
+static void pci_rescan_slot(struct pci_dev *temp)
+{
+       struct pci_bus *bus = temp->bus;
+       struct pci_dev *dev;
+       int func;
+       u8 hdr_type;
+       if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
+               temp->hdr_type = hdr_type & 0x7f;
+               if (!pci_find_slot(bus->number, temp->devfn)) {
+                       dev = pci_scan_single_device(bus, temp->devfn);
+                       if (dev) {
+                               dbg("New device on %s function %x:%x\n",
+                                       bus->name, temp->devfn >> 3,
+                                       temp->devfn & 7);
+                               pci_bus_add_device(dev);
+                               add_slot(dev);
+                       }
+               }
+               /* multifunction device? */
+               if (!(hdr_type & 0x80))
+                       return;
+
+               /* continue scanning for other functions */
+               for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) {
+                       if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
+                               continue;
+                       temp->hdr_type = hdr_type & 0x7f;
+
+                       if (!pci_find_slot(bus->number, temp->devfn)) {
+                               dev = pci_scan_single_device(bus, temp->devfn);
+                               if (dev) {
+                                       dbg("New device on %s function %x:%x\n",
+                                               bus->name, temp->devfn >> 3,
+                                               temp->devfn & 7);
+                                       pci_bus_add_device(dev);
+                                       add_slot(dev);
+                               }
+                       }
+               }
+       }
+}
+
+
+/**
+ * Rescan PCI bus.
+ * call pci_rescan_slot for each possible function of the bus
+ *
+ * @param bus
+ */
+static void pci_rescan_bus(const struct pci_bus *bus)
+{
+       unsigned int devfn;
+       struct pci_dev *dev;
+       dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+       if (!dev)
+               return;
+
+       memset(dev, 0, sizeof(dev));
+       dev->bus = (struct pci_bus*)bus;
+       dev->sysdata = bus->sysdata;
+       for (devfn = 0; devfn < 0x100; devfn += 8) {
+               dev->devfn = devfn;
+               pci_rescan_slot(dev);
+       }
+       kfree(dev);
+}
+
+/* recursively scan all buses */
+static void pci_rescan_buses(const struct list_head *list)
+{
+       const struct list_head *l;
+       list_for_each(l,list) {
+               const struct pci_bus *b = pci_bus_b(l);
+               pci_rescan_bus(b);
+               pci_rescan_buses(&b->children);
+       }
+}
+
+/* initiate rescan of all pci buses */
+static inline void pci_rescan(void) {
+       pci_rescan_buses(&pci_root_buses);
+}
+
+
 static int enable_slot(struct hotplug_slot *hotplug_slot)
 {
+       /* mis-use enable_slot for rescanning of the pci bus */
+       pci_rescan();
        return -ENODEV;
 }
 
+/* find the hotplug_slot for the pci_dev */
+static struct hotplug_slot *get_slot_from_dev(struct pci_dev *dev)
+{
+       struct dummy_slot *dslot;
+
+       list_for_each_entry(dslot, &slot_list, node) {
+               if (dslot->dev == dev)
+                       return dslot->slot;
+       }
+       return NULL;
+}
+
+
 static int disable_slot(struct hotplug_slot *slot)
 {
        struct dummy_slot *dslot;
+       struct hotplug_slot *hslot;
+       struct pci_dev *dev;
+       int func;
 
        if (!slot)
                return -ENODEV;
@@ -185,6 +294,23 @@ static int disable_slot(struct hotplug_slot *slot)
                err("Can't remove PCI devices with other PCI devices behind it yet.\n");
                return -ENODEV;
        }
+       /* search for subfunctions and disable them first */
+       if (!(dslot->dev->devfn & 7)) {
+               for (func = 1; func < 8; func++) {
+                       dev = pci_find_slot(dslot->dev->bus->number,
+                                       dslot->dev->devfn + func);
+                       if (dev) {
+                               hslot = get_slot_from_dev(dev);
+                               if (hslot)
+                                       disable_slot(hslot);
+                               else {
+                                       err("Hotplug slot not found for subfunction of PCI device\n");
+                                       return -ENODEV;
+                               }
+                       } else
+                               dbg("No device in slot found\n");
+               }
+       }
 
        /* remove the device from the pci core */
        pci_remove_bus_device(dslot->dev);
@@ -227,6 +353,6 @@ module_exit(dummyphp_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
 
index 470e9af..aea1187 100644 (file)
@@ -63,7 +63,7 @@ static LIST_HEAD (rio_vg_head);
 static LIST_HEAD (rio_lo_head);
 static LIST_HEAD (opt_vg_head);
 static LIST_HEAD (opt_lo_head);
-static void *io_mem;
+static void __iomem *io_mem;
 
 /* Local functions */
 static int ebda_rsrc_controller (void);
@@ -1246,7 +1246,7 @@ int ibmphp_register_pci (void)
        list_for_each (tmp, &ebda_hpc_head) {
                ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
                if (ctrl->ctlr_type == 1) {
-                       rc = pci_module_init (&ibmphp_driver);
+                       rc = pci_register_driver(&ibmphp_driver);
                        break;
                }
        }
index 3a7a528..bef21ae 100644 (file)
@@ -152,7 +152,7 @@ struct msi_desc {
                __u16   tail;
        }link;
 
-       unsigned long mask_base;
+       void __iomem *mask_base;
        struct pci_dev *dev;
 };
 
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);
index 889b2e3..b2942c4 100644 (file)
@@ -16,6 +16,7 @@ static void pci_free_resources(struct pci_dev *dev)
 
        msi_remove_pci_irq_vectors(dev);
 
+       pci_cleanup_rom(dev);
        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
                struct resource *res = dev->resource + i;
                if (res->parent)
@@ -26,6 +27,7 @@ static void pci_free_resources(struct pci_dev *dev)
 static void pci_destroy_dev(struct pci_dev *dev)
 {
        pci_proc_detach_device(dev);
+       pci_remove_sysfs_dev_files(dev);
        device_unregister(&dev->dev);
 
        /* Remove the device from the device lists, and prevent any further
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);
index e21250c..830baa2 100644 (file)
@@ -533,16 +533,16 @@ EXPORT_SYMBOL(pci_bus_assign_resources);
 void __init
 pci_assign_unassigned_resources(void)
 {
-       struct list_head *ln;
+       struct pci_bus *bus;
 
        /* Depth first, calculate sizes and alignments of all
           subordinate buses. */
-       list_for_each(ln, &pci_root_buses) {
-               pci_bus_size_bridges(pci_bus_b(ln));
+       list_for_each_entry(bus, &pci_root_buses, node) {
+               pci_bus_size_bridges(bus);
        }
        /* Depth last, allocate resources and update the hardware. */
-       list_for_each(ln, &pci_root_buses) {
-               pci_bus_assign_resources(pci_bus_b(ln));
-               pci_enable_bridges(pci_bus_b(ln));
+       list_for_each_entry(bus, &pci_root_buses, node) {
+               pci_bus_assign_resources(bus);
+               pci_enable_bridges(bus);
        }
 }
index c2ddc50..677f1e7 100644 (file)
@@ -65,7 +65,7 @@ pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
               int (*map_irq)(struct pci_dev *, u8, u8))
 {
        struct pci_dev *dev = NULL;
-       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
                pdev_fixup_irq(dev, swizzle, map_irq);
        }
 }
index 42a5ad4..9fbf0d2 100644 (file)
@@ -56,7 +56,7 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
        if (resno < 6) {
                reg = PCI_BASE_ADDRESS_0 + 4 * resno;
        } else if (resno == PCI_ROM_RESOURCE) {
-               new |= res->flags & PCI_ROM_ADDRESS_ENABLE;
+               new |= res->flags & IORESOURCE_ROM_ENABLE;
                reg = dev->rom_base_reg;
        } else {
                /* Hmm, non-standard resource. */
index 3298828..855c1f7 100644 (file)
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
-static void retry_erase_list(erase_busy_t *list, u_int cause);
-
-/*======================================================================
-
-    This function handles submitting an MTD request, and retrying
-    requests when an MTD is busy.
-
-    An MTD request should never block.
-    
-======================================================================*/
-
-static int do_mtd_request(memory_handle_t handle, mtd_request_t *req,
-                         caddr_t buf)
-{
-    int ret, tries;
-    client_t *mtd;
-    struct pcmcia_socket *s;
-    
-    mtd = handle->mtd;
-    if (mtd == NULL)
-       return CS_GENERAL_FAILURE;
-    s = SOCKET(mtd);
-    for (ret = tries = 0; tries < 100; tries++) {
-       mtd->event_callback_args.mtdrequest = req;
-       mtd->event_callback_args.buffer = buf;
-       ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
-       if (ret != CS_BUSY)
-           break;
-       switch (req->Status) {
-       case MTD_WAITREQ:
-           /* Not that we should ever need this... */
-           interruptible_sleep_on_timeout(&mtd->mtd_req, HZ);
-           break;
-       case MTD_WAITTIMER:
-       case MTD_WAITRDY:
-           interruptible_sleep_on_timeout(&mtd->mtd_req, req->Timeout*HZ/1000);
-           req->Function |= MTD_REQ_TIMEOUT;
-           break;
-       case MTD_WAITPOWER:
-           interruptible_sleep_on(&mtd->mtd_req);
-           break;
-       }
-       if (signal_pending(current))
-           printk(KERN_NOTICE "cs: do_mtd_request interrupted!\n");
-    }
-    if (tries == 20) {
-       printk(KERN_NOTICE "cs: MTD request timed out!\n");
-       ret = CS_GENERAL_FAILURE;
-    }
-    wake_up_interruptible(&mtd->mtd_req);
-    retry_erase_list(&mtd->erase_busy, 0);
-    return ret;
-} /* do_mtd_request */
-
-/*======================================================================
-
-    This stuff is all for handling asynchronous erase requests.  It
-    is complicated because all the retry stuff has to be dealt with
-    in timer interrupts or in the card status event handler.
-
-======================================================================*/
-
-static void insert_queue(struct pcmcia_socket *s, erase_busy_t *head, erase_busy_t *entry)
-{
-    cs_dbg(s, 2, "adding 0x%p to queue 0x%p\n", entry, head);
-    entry->next = head;
-    entry->prev = head->prev;
-    head->prev->next = entry;
-    head->prev = entry;
-}
-
-static void remove_queue(struct pcmcia_socket *s, erase_busy_t *entry)
-{
-    cs_dbg(s, 2, "unqueueing 0x%p\n", entry);
-    entry->next->prev = entry->prev;
-    entry->prev->next = entry->next;
-}
-
-static void retry_erase(erase_busy_t *busy, u_int cause)
-{
-    eraseq_entry_t *erase = busy->erase;
-    mtd_request_t req;
-    client_t *mtd;
-    struct pcmcia_socket *s;
-    int ret;
-
-    mtd = erase->Handle->mtd;
-    s = SOCKET(mtd);
-
-    cs_dbg(s, 2, "trying erase request 0x%p...\n", busy);
-    if (busy->next)
-       remove_queue(s, busy);
-    req.Function = MTD_REQ_ERASE | cause;
-    req.TransferLength = erase->Size;
-    req.DestCardOffset = erase->Offset + erase->Handle->info.CardOffset;
-    req.MediaID = erase->Handle->MediaID;
-    mtd->event_callback_args.mtdrequest = &req;
-    ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
-    if (ret == CS_BUSY) {
-       cs_dbg(s, 2, "  Status = %d, requeueing.\n", req.Status);
-       switch (req.Status) {
-       case MTD_WAITREQ:
-       case MTD_WAITPOWER:
-           insert_queue(s, &mtd->erase_busy, busy);
-           break;
-       case MTD_WAITTIMER:
-       case MTD_WAITRDY:
-           if (req.Status == MTD_WAITRDY)
-               insert_queue(s, &s->erase_busy, busy);
-           mod_timer(&busy->timeout, jiffies + req.Timeout*HZ/1000);
-           break;
-       }
-    } else {
-       /* update erase queue status */
-       cs_dbg(s, 2, "  Ret = %d\n", ret);
-       switch (ret) {
-       case CS_SUCCESS:
-           erase->State = ERASE_PASSED; break;
-       case CS_WRITE_PROTECTED:
-           erase->State = ERASE_MEDIA_WRPROT; break;
-       case CS_BAD_OFFSET:
-           erase->State = ERASE_BAD_OFFSET; break;
-       case CS_BAD_SIZE:
-           erase->State = ERASE_BAD_SIZE; break;
-       case CS_NO_CARD:
-           erase->State = ERASE_BAD_SOCKET; break;
-       default:
-           erase->State = ERASE_FAILED; break;
-       }
-       busy->client->event_callback_args.info = erase;
-       EVENT(busy->client, CS_EVENT_ERASE_COMPLETE, CS_EVENT_PRI_LOW);
-       kfree(busy);
-       /* Resubmit anything waiting for a request to finish */
-       wake_up_interruptible(&mtd->mtd_req);
-       retry_erase_list(&mtd->erase_busy, 0);
-    }
-} /* retry_erase */
-
-static void retry_erase_list(erase_busy_t *list, u_int cause)
-{
-    erase_busy_t tmp = *list;
-
-    cs_dbg(SOCKET(list->client), 2, "rescanning erase queue list 0x%p\n", list);
-    if (list->next == list)
-       return;
-    /* First, truncate the original list */
-    list->prev->next = &tmp;
-    list->next->prev = &tmp;
-    list->prev = list->next = list;
-    tmp.prev->next = &tmp;
-    tmp.next->prev = &tmp;
-
-    /* Now, retry each request, in order. */
-    while (tmp.next != &tmp)
-       retry_erase(tmp.next, cause);
-} /* retry_erase_list */
-
-static void handle_erase_timeout(u_long arg)
-{
-    erase_busy_t *busy = (erase_busy_t *)arg;
-    cs_dbg(SOCKET(busy->client), 0, "erase timeout for entry 0x%lx\n", arg);
-    retry_erase(busy, MTD_REQ_TIMEOUT);
-}
-
-static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
-{
-    erase_busy_t *busy;
-    region_info_t *info;
-    
-    if (CHECK_REGION(erase->Handle))
-       erase->State = ERASE_BAD_SOCKET;
-    else {
-       info = &erase->Handle->info;
-       if ((erase->Offset >= info->RegionSize) ||
-           (erase->Offset & (info->BlockSize-1)))
-           erase->State = ERASE_BAD_OFFSET;
-       else if ((erase->Offset+erase->Size > info->RegionSize) ||
-                (erase->Size & (info->BlockSize-1)))
-           erase->State = ERASE_BAD_SIZE;
-       else {
-           erase->State = 1;
-           busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
-           if (!busy) {
-               erase->State = ERASE_FAILED;
-               return;
-           }
-           busy->erase = erase;
-           busy->client = handle;
-           init_timer(&busy->timeout);
-           busy->timeout.data = (u_long)busy;
-           busy->timeout.function = &handle_erase_timeout;
-           busy->prev = busy->next = NULL;
-           retry_erase(busy, 0);
-       }
-    }
-} /* setup_erase_request */
-
-/*======================================================================
-
-    MTD helper functions
-
-======================================================================*/
-
-static int mtd_modify_window(window_handle_t win, mtd_mod_win_t *req)
-{
-    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-       return CS_BAD_HANDLE;
-    win->ctl.flags = MAP_16BIT | MAP_ACTIVE;
-    if (req->Attributes & WIN_USE_WAIT)
-       win->ctl.flags |= MAP_USE_WAIT;
-    if (req->Attributes & WIN_MEMORY_TYPE)
-       win->ctl.flags |= MAP_ATTRIB;
-    win->ctl.speed = req->AccessSpeed;
-    win->ctl.card_start = req->CardOffset;
-    win->sock->ops->set_mem_map(win->sock, &win->ctl);
-    return CS_SUCCESS;
-}
-
-static int mtd_set_vpp(client_handle_t handle, mtd_vpp_req_t *req)
-{
-    struct pcmcia_socket *s;
-    if (CHECK_HANDLE(handle))
-       return CS_BAD_HANDLE;
-    if (req->Vpp1 != req->Vpp2)
-       return CS_BAD_VPP;
-    s = SOCKET(handle);
-    s->socket.Vpp = req->Vpp1;
-    if (s->ops->set_socket(s, &s->socket))
-       return CS_BAD_VPP;
-    return CS_SUCCESS;
-}
-
-static int mtd_rdy_mask(client_handle_t handle, mtd_rdy_req_t *req)
-{
-    struct pcmcia_socket *s;
-    if (CHECK_HANDLE(handle))
-       return CS_BAD_HANDLE;
-    s = SOCKET(handle);
-    if (req->Mask & CS_EVENT_READY_CHANGE)
-       s->socket.csc_mask |= SS_READY;
-    else
-       s->socket.csc_mask &= ~SS_READY;
-    if (s->ops->set_socket(s, &s->socket))
-       return CS_GENERAL_FAILURE;
-    return CS_SUCCESS;
-}
-
-int MTDHelperEntry(int func, void *a1, void *a2)
-{
-    switch (func) {
-    case MTDRequestWindow:
-    {
-       window_handle_t w;
-        int ret = pcmcia_request_window(a1, a2, &w);
-        a1 = w;
-       return  ret;
-    }
-        break;
-    case MTDReleaseWindow:
-       return pcmcia_release_window(a1);
-    case MTDModifyWindow:
-       return mtd_modify_window(a1, a2); break;
-    case MTDSetVpp:
-       return mtd_set_vpp(a1, a2); break;
-    case MTDRDYMask:
-       return mtd_rdy_mask(a1, a2); break;
-    default:
-       return CS_UNSUPPORTED_FUNCTION; break;
-    }
-} /* MTDHelperEntry */
+#ifdef DEBUG
+extern int ds_pc_debug;
+#define cs_socket_name(skt)    ((skt)->dev.class_id)
+
+#define ds_dbg(skt, lvl, fmt, arg...) do {             \
+       if (ds_pc_debug >= lvl)                         \
+               printk(KERN_DEBUG "ds: %s: " fmt,       \
+                      cs_socket_name(skt) , ## arg);   \
+} while (0)
+#else
+#define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#endif
 
 /*======================================================================
 
@@ -327,8 +69,8 @@ int MTDHelperEntry(int func, void *a1, void *a2)
     
 ======================================================================*/
 
-static void setup_regions(client_handle_t handle, int attr,
-                         memory_handle_t *list)
+static void setup_regions(struct pcmcia_socket *s, unsigned int function,
+                         int attr,  memory_handle_t *list)
 {
     int i, code, has_jedec, has_geo;
     u_int offset;
@@ -337,22 +79,22 @@ static void setup_regions(client_handle_t handle, int attr,
     cistpl_device_geo_t geo;
     memory_handle_t r;
 
-    cs_dbg(SOCKET(handle), 1, "setup_regions(0x%p, %d, 0x%p)\n",
-          handle, attr, list);
+    ds_dbg(s, 1, "setup_regions(0x%d, %d, 0x%p)\n",
+          function, attr, list);
 
     code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
-    if (read_tuple(handle, code, &device) != CS_SUCCESS)
+    if (pccard_read_tuple(s, function, code, &device) != CS_SUCCESS)
        return;
     code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
-    has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
+    has_jedec = (pccard_read_tuple(s, function, code, &jedec) == CS_SUCCESS);
     if (has_jedec && (device.ndev != jedec.nid)) {
-       cs_dbg(SOCKET(handle), 0, "Device info does not match JEDEC info.\n");
+       ds_dbg(s, 0, "Device info does not match JEDEC info.\n");
        has_jedec = 0;
     }
     code = (attr) ? CISTPL_DEVICE_GEO_A : CISTPL_DEVICE_GEO;
-    has_geo = (read_tuple(handle, code, &geo) == CS_SUCCESS);
+    has_geo = (pccard_read_tuple(s, function, code, &geo) == CS_SUCCESS);
     if (has_geo && (device.ndev != geo.ngeo)) {
-       cs_dbg(SOCKET(handle), 0, "Device info does not match geometry tuple.\n");
+       ds_dbg(s, 0, "Device info does not match geometry tuple.\n");
        has_geo = 0;
     }
     
@@ -400,6 +142,37 @@ static void setup_regions(client_handle_t handle, int attr,
     
 ======================================================================*/
 
+static int pccard_match_region(memory_handle_t list, region_info_t *match)
+{
+       if (list) {
+               *match = list->info;
+               return CS_SUCCESS;
+       }
+       return CS_NO_MORE_ITEMS;
+} /* match_region */
+
+int pccard_get_first_region(struct pcmcia_socket *s, region_info_t *rgn)
+{
+       if (!(s->state & SOCKET_REGION_INFO)) {
+               setup_regions(s, BIND_FN_ALL, 0, &s->c_region);
+               setup_regions(s, BIND_FN_ALL, 1, &s->a_region);
+               s->state |= SOCKET_REGION_INFO;
+       }
+
+       if (rgn->Attributes & REGION_TYPE_AM)
+               return pccard_match_region(s->a_region, rgn);
+       else
+               return pccard_match_region(s->c_region, rgn);
+} /* get_first_region */
+
+int pccard_get_next_region(struct pcmcia_socket *s, region_info_t *rgn)
+{
+    return pccard_match_region(rgn->next, rgn);
+} /* get_next_region */
+
+
+#ifdef CONFIG_PCMCIA_OBSOLETE
+
 static int match_region(client_handle_t handle, memory_handle_t list,
                        region_info_t *match)
 {
@@ -422,8 +195,8 @@ int pcmcia_get_first_region(client_handle_t handle, region_info_t *rgn)
     
     if ((handle->Attributes & INFO_MASTER_CLIENT) &&
        (!(s->state & SOCKET_REGION_INFO))) {
-       setup_regions(handle, 0, &s->c_region);
-       setup_regions(handle, 1, &s->a_region);
+       setup_regions(s, handle->Function, 0, &s->c_region);
+       setup_regions(s, handle->Function, 1, &s->a_region);
        s->state |= SOCKET_REGION_INFO;
     }
 
@@ -432,6 +205,7 @@ int pcmcia_get_first_region(client_handle_t handle, region_info_t *rgn)
     else
        return match_region(handle, s->c_region, rgn);
 } /* get_first_region */
+EXPORT_SYMBOL(pcmcia_get_first_region);
 
 int pcmcia_get_next_region(client_handle_t handle, region_info_t *rgn)
 {
@@ -439,200 +213,6 @@ int pcmcia_get_next_region(client_handle_t handle, region_info_t *rgn)
        return CS_BAD_HANDLE;
     return match_region(handle, rgn->next, rgn);
 } /* get_next_region */
+EXPORT_SYMBOL(pcmcia_get_next_region);
 
-/*======================================================================
-
-    Connect an MTD with a memory region.
-    
-======================================================================*/
-
-int pcmcia_register_mtd(client_handle_t handle, mtd_reg_t *reg)
-{
-    memory_handle_t list;
-    struct pcmcia_socket *s;
-    
-    if (CHECK_HANDLE(handle))
-       return CS_BAD_HANDLE;
-    s = SOCKET(handle);
-    if (reg->Attributes & REGION_TYPE_AM)
-       list = s->a_region;
-    else
-       list = s->c_region;
-    cs_dbg(s, 1, "register_mtd(0x%p, '%s', 0x%x)\n",
-         handle, handle->dev_info, reg->Offset);
-    while (list) {
-       if (list->info.CardOffset == reg->Offset) break;
-       list = list->info.next;
-    }
-    if (list && (list->mtd == NULL) &&
-       (strcmp(handle->dev_info, list->dev_info) == 0)) {
-       list->info.Attributes = reg->Attributes;
-       list->MediaID = reg->MediaID;
-       list->mtd = handle;
-       handle->mtd_count++;
-       return CS_SUCCESS;
-    } else
-       return CS_BAD_OFFSET;
-} /* register_mtd */
-
-/*======================================================================
-
-    Erase queue management functions
-    
-======================================================================*/
-
-int pcmcia_register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header,
-                                 eraseq_handle_t *e)
-{
-    eraseq_t *queue;
-
-    if ((handle == NULL) || CHECK_HANDLE(*handle))
-       return CS_BAD_HANDLE;
-    queue = kmalloc(sizeof(*queue), GFP_KERNEL);
-    if (!queue) return CS_OUT_OF_RESOURCE;
-    queue->eraseq_magic = ERASEQ_MAGIC;
-    queue->handle = *handle;
-    queue->count = header->QueueEntryCnt;
-    queue->entry = header->QueueEntryArray;
-    *e = queue;
-    return CS_SUCCESS;
-} /* register_erase_queue */
-
-int pcmcia_deregister_erase_queue(eraseq_handle_t eraseq)
-{
-    int i;
-    if (CHECK_ERASEQ(eraseq))
-       return CS_BAD_HANDLE;
-    for (i = 0; i < eraseq->count; i++)
-       if (ERASE_IN_PROGRESS(eraseq->entry[i].State)) break;
-    if (i < eraseq->count)
-       return CS_BUSY;
-    eraseq->eraseq_magic = 0;
-    kfree(eraseq);
-    return CS_SUCCESS;
-} /* deregister_erase_queue */
-
-int pcmcia_check_erase_queue(eraseq_handle_t eraseq)
-{
-    int i;
-    if (CHECK_ERASEQ(eraseq))
-       return CS_BAD_HANDLE;
-    for (i = 0; i < eraseq->count; i++)
-       if (eraseq->entry[i].State == ERASE_QUEUED)
-           setup_erase_request(eraseq->handle, &eraseq->entry[i]);
-    return CS_SUCCESS;
-} /* check_erase_queue */
-
-/*======================================================================
-
-    Look up the memory region matching the request, and return a
-    memory handle.
-    
-======================================================================*/
-
-int pcmcia_open_memory(client_handle_t *handle, open_mem_t *open, memory_handle_t *mh)
-{
-    struct pcmcia_socket *s;
-    memory_handle_t region;
-    
-    if ((handle == NULL) || CHECK_HANDLE(*handle))
-       return CS_BAD_HANDLE;
-    s = (*handle)->Socket;
-    if (open->Attributes & MEMORY_TYPE_AM)
-       region = s->a_region;
-    else
-       region = s->c_region;
-    while (region) {
-       if (region->info.CardOffset == open->Offset) break;
-       region = region->info.next;
-    }
-    if (region && region->mtd) {
-       *mh = region;
-       cs_dbg(s, 1, "open_memory(0x%p, 0x%x) = 0x%p\n",
-              handle, open->Offset, region);
-       return CS_SUCCESS;
-    } else
-       return CS_BAD_OFFSET;
-} /* open_memory */
-
-/*======================================================================
-
-    Close a memory handle from an earlier call to OpenMemory.
-    
-    For the moment, I don't think this needs to do anything.
-    
-======================================================================*/
-
-int pcmcia_close_memory(memory_handle_t handle)
-{
-    cs_dbg(SOCKET(handle->mtd), 1, "cs: close_memory(0x%p)\n", handle);
-    if (CHECK_REGION(handle))
-       return CS_BAD_HANDLE;
-    return CS_SUCCESS;
-} /* close_memory */
-
-/*======================================================================
-
-    Read from a memory device, using a handle previously returned
-    by a call to OpenMemory.
-    
-======================================================================*/
-
-int pcmcia_read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
-{
-    mtd_request_t mtd;
-    if (CHECK_REGION(handle))
-       return CS_BAD_HANDLE;
-    if (req->Offset >= handle->info.RegionSize)
-       return CS_BAD_OFFSET;
-    if (req->Offset+req->Count > handle->info.RegionSize)
-       return CS_BAD_SIZE;
-    
-    mtd.SrcCardOffset = req->Offset + handle->info.CardOffset;
-    mtd.TransferLength = req->Count;
-    mtd.MediaID = handle->MediaID;
-    mtd.Function = MTD_REQ_READ;
-    if (req->Attributes & MEM_OP_BUFFER_KERNEL)
-       mtd.Function |= MTD_REQ_KERNEL;
-    return do_mtd_request(handle, &mtd, buf);
-} /* read_memory */
-
-/*======================================================================
-
-    Write to a memory device, using a handle previously returned by
-    a call to OpenMemory.
-    
-======================================================================*/
-
-int pcmcia_write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
-{
-    mtd_request_t mtd;
-    if (CHECK_REGION(handle))
-       return CS_BAD_HANDLE;
-    if (req->Offset >= handle->info.RegionSize)
-       return CS_BAD_OFFSET;
-    if (req->Offset+req->Count > handle->info.RegionSize)
-       return CS_BAD_SIZE;
-    
-    mtd.DestCardOffset = req->Offset + handle->info.CardOffset;
-    mtd.TransferLength = req->Count;
-    mtd.MediaID = handle->MediaID;
-    mtd.Function = MTD_REQ_WRITE;
-    if (req->Attributes & MEM_OP_BUFFER_KERNEL)
-       mtd.Function |= MTD_REQ_KERNEL;
-    return do_mtd_request(handle, &mtd, buf);
-} /* write_memory */
-
-/*======================================================================
-
-    This isn't needed for anything I could think of.
-    
-======================================================================*/
-
-int pcmcia_copy_memory(memory_handle_t handle, copy_op_t *req)
-{
-    if (CHECK_REGION(handle))
-       return CS_BAD_HANDLE;
-    return CS_UNSUPPORTED_FUNCTION;
-}
-
+#endif
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
index 2bdf9a0..a6936a7 100644 (file)
@@ -217,7 +217,13 @@ static int pxa2xx_drv_pcmcia_resume(struct device *dev, u32 level)
 {
        int ret = 0;
        if (level == RESUME_RESTORE_STATE)
+       {
+               struct pcmcia_low_level *ops = dev->platform_data;
+               int nr = ops ? ops->nr : 0;
+
+               MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0);
                ret = pcmcia_socket_dev_resume(dev);
+       }
        return ret;
 }
 
index 48726e7..fd1f691 100644 (file)
@@ -265,3 +265,5 @@ int __init pcmcia_lubbock_init(struct sa1111_dev *sadev)
 
        return ret;
 }
+
+MODULE_LICENSE("GPL");
index 7f04a6b..4e637ee 100644 (file)
@@ -120,7 +120,7 @@ struct yenta_socket {
        unsigned int private[8];
 
        /* PCI saved state */
-       u32 saved_state[18];
+       u32 saved_state[2];
 };
 
 
index 7e227ec..6776308 100644 (file)
@@ -6,7 +6,7 @@ menu "Plug and Play support"
 
 config PNP
        bool "Plug and Play support"
-       depends on ISA
+       depends on ISA || ACPI_BUS
        ---help---
          Plug and Play (PnP) is a standard for peripherals which allows those
          peripherals to be configured by software, e.g. assign IRQ's or other
@@ -35,5 +35,7 @@ source "drivers/pnp/isapnp/Kconfig"
 
 source "drivers/pnp/pnpbios/Kconfig"
 
+source "drivers/pnp/pnpacpi/Kconfig"
+
 endmenu
 
index a83a4fb..a381a92 100644 (file)
@@ -4,5 +4,6 @@
 
 obj-y          := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o system.o
 
+obj-$(CONFIG_PNPACPI)          += pnpacpi/
 obj-$(CONFIG_PNPBIOS)          += pnpbios/
 obj-$(CONFIG_ISAPNP)           += isapnp/
index f7548c4..8527ae6 100644 (file)
@@ -60,8 +60,8 @@ static void pnp_print_irq(pnp_info_buffer_t *buffer, char *space, struct pnp_irq
        int first = 1, i;
 
        pnp_printf(buffer, "%sirq ", space);
-       for (i = 0; i < 16; i++)
-               if (irq->map & (1<<i)) {
+       for (i = 0; i < PNP_IRQ_NR; i++)
+               if (test_bit(i, irq->map)) {
                        if (!first) {
                                pnp_printf(buffer, ",");
                        } else {
@@ -72,7 +72,7 @@ static void pnp_print_irq(pnp_info_buffer_t *buffer, char *space, struct pnp_irq
                        else
                                pnp_printf(buffer, "%i", i);
                }
-       if (!irq->map)
+       if (bitmap_empty(irq->map, PNP_IRQ_NR))
                pnp_printf(buffer, "<none>");
        if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
                pnp_printf(buffer, " High-Edge");
index 50cc779..578651e 100644 (file)
@@ -3,7 +3,7 @@
 #
 config ISAPNP
        bool "ISA Plug and Play support"
-       depends on PNP
+       depends on PNP && ISA
        help
          Say Y here if you would like support for ISA Plug and Play devices.
          Some information is in <file:Documentation/isapnp.txt>.
index b31a33a..0cbdf9d 100644 (file)
@@ -150,13 +150,19 @@ static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
        *flags |= rule->flags | IORESOURCE_IRQ;
        *flags &=  ~IORESOURCE_UNSET;
 
-       if (!rule->map) {
+       if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
                *flags |= IORESOURCE_DISABLED;
                return 1; /* skip disabled resource requests */
        }
 
+       /* TBD: need check for >16 IRQ */
+       *start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
+       if (*start < PNP_IRQ_NR) {
+               *end = *start;
+               return 1;
+       }
        for (i = 0; i < 16; i++) {
-               if(rule->map & (1<<xtab[i])) {
+               if(test_bit(xtab[i], rule->map)) {
                        *start = *end = xtab[i];
                        if(pnp_check_irq(dev, idx))
                                return 1;
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;
+}
index 7aafbf8..3c7f977 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/ctype.h>
 #include <linux/pnp.h>
 #include <linux/pnpbios.h>
+#include <linux/pci.h>
 
 #include "pnpbios.h"
 
@@ -58,6 +59,7 @@ pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
                }
                res->irq_resource[i].start =
                res->irq_resource[i].end = (unsigned long) irq;
+               pcibios_penalize_isa_irq(irq);
        }
 }
 
@@ -285,10 +287,13 @@ static void
 pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
 {
        struct pnp_irq * irq;
+       unsigned long bits;
+
        irq = pnpbios_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
        if (!irq)
                return;
-       irq->map = (p[2] << 8) | p[1];
+       bits = (p[2] << 8) | p[1];
+       bitmap_copy(irq->map, &bits, 16);
        if (size > 2)
                irq->flags = p[3];
        else
index 74eecb2..596a02d 100644 (file)
@@ -63,14 +63,17 @@ static void quirk_awe32_resources(struct pnp_dev *dev)
 static void quirk_cmi8330_resources(struct pnp_dev *dev)
 {
        struct pnp_option *res = dev->dependent;
+       unsigned long tmp;
 
        for ( ; res ; res = res->next ) {
 
                struct pnp_irq *irq;
                struct pnp_dma *dma;
 
-               for( irq = res->irq; irq; irq = irq->next )     // Valid irqs are 5, 7, 10
-                       irq->map = 0x04A0;                                              // 0000 0100 1010 0000
+               for( irq = res->irq; irq; irq = irq->next ) {   // Valid irqs are 5, 7, 10
+                       tmp = 0x04A0;
+                       bitmap_copy(irq->map, &tmp, 16);        // 0000 0100 1010 0000
+               }
 
                for( dma = res->dma; dma; dma = dma->next ) // Valid 8bit dma channels are 1,3
                        if( ( dma->flags & IORESOURCE_DMA_TYPE_MASK ) == IORESOURCE_DMA_8BIT )
index 3fc9f6c..80a6979 100644 (file)
@@ -101,8 +101,8 @@ int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
        {
                int i;
 
-               for (i=0; i<16; i++)
-                       if (data->map & (1<<i))
+               for (i = 0; i < 16; i++)
+                       if (test_bit(i, data->map))
                                pcibios_penalize_isa_irq(i);
        }
 #endif
@@ -421,6 +421,7 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
 
 int pnp_check_dma(struct pnp_dev * dev, int idx)
 {
+#ifndef CONFIG_IA64
        int tmp;
        struct pnp_dev *tdev;
        unsigned long * dma = &dev->res.dma_resource[idx].start;
@@ -470,6 +471,10 @@ int pnp_check_dma(struct pnp_dev * dev, int idx)
        }
 
        return 1;
+#else
+       /* IA64 hasn't legacy DMA */
+       return 0;
+#endif
 }
 
 
index b7a764c..a66b17b 100644 (file)
@@ -139,6 +139,57 @@ dcssblk_get_device_by_name(char *name)
        return NULL;
 }
 
+/*
+ * print appropriate error message for segment_load()/segment_type()
+ * return code
+ */
+static void
+dcssblk_segment_warn(int rc, char* seg_name)
+{
+       switch (rc) {
+       case -ENOENT:
+               PRINT_WARN("cannot load/query segment %s, does not exist\n",
+                          seg_name);
+               break;
+       case -ENOSYS:
+               PRINT_WARN("cannot load/query segment %s, not running on VM\n",
+                          seg_name);
+               break;
+       case -EIO:
+               PRINT_WARN("cannot load/query segment %s, hardware error\n",
+                          seg_name);
+               break;
+       case -ENOTSUPP:
+               PRINT_WARN("cannot load/query segment %s, is a multi-part "
+                          "segment\n", seg_name);
+               break;
+       case -ENOSPC:
+               PRINT_WARN("cannot load/query segment %s, overlaps with "
+                          "storage\n", seg_name);
+               break;
+       case -EBUSY:
+               PRINT_WARN("cannot load/query segment %s, overlaps with "
+                          "already loaded dcss\n", seg_name);
+               break;
+       case -EPERM:
+               PRINT_WARN("cannot load/query segment %s, already loaded in "
+                          "incompatible mode\n", seg_name);
+               break;
+       case -ENOMEM:
+               PRINT_WARN("cannot load/query segment %s, out of memory\n",
+                          seg_name);
+               break;
+       case -ERANGE:
+               PRINT_WARN("cannot load/query segment %s, exceeds kernel "
+                          "mapping range\n", seg_name);
+               break;
+       default:
+               PRINT_WARN("cannot load/query segment %s, return value %i\n",
+                          seg_name, rc);
+               break;
+       }
+}
+
 /*
  * device attribute for switching shared/nonshared (exclusive)
  * operation (show + store)
@@ -167,80 +218,50 @@ dcssblk_shared_store(struct device *dev, const char *inbuf, size_t count)
        if (atomic_read(&dev_info->use_count)) {
                PRINT_ERR("share: segment %s is busy!\n",
                          dev_info->segment_name);
-               up_write(&dcssblk_devices_sem);
-               return -EBUSY;
-       }
-       if ((inbuf[0] == '1') && (dev_info->is_shared == 1)) {
-               PRINT_WARN("Segment %s already loaded in shared mode!\n",
-                          dev_info->segment_name);
-               up_write(&dcssblk_devices_sem);
-               return count;
-       }
-       if ((inbuf[0] == '0') && (dev_info->is_shared == 0)) {
-               PRINT_WARN("Segment %s already loaded in exclusive mode!\n",
-                          dev_info->segment_name);
-               up_write(&dcssblk_devices_sem);
-               return count;
+               rc = -EBUSY;
+               goto out;
        }
        if (inbuf[0] == '1') {
                // reload segment in shared mode
-               segment_unload(dev_info->segment_name);
-               rc = segment_load(dev_info->segment_name, SEGMENT_SHARED_RO,
-                                       &dev_info->start, &dev_info->end);
+               rc = segment_modify_shared(dev_info->segment_name,
+                                          SEGMENT_SHARED);
                if (rc < 0) {
-                       PRINT_ERR("Segment %s not reloaded, rc=%d\n",
-                                       dev_info->segment_name, rc);
-                       goto removeseg;
+                       BUG_ON(rc == -EINVAL);
+                       if (rc == -EIO || rc == -ENOENT)
+                               goto removeseg;
+               } else {
+                       dev_info->is_shared = 1;
+                       switch (dev_info->segment_type) {
+                               case SEG_TYPE_SR:
+                               case SEG_TYPE_ER:
+                               case SEG_TYPE_SC:
+                                       set_disk_ro(dev_info->gd,1);
+                       }
                }
-               dev_info->is_shared = 1;
-               PRINT_INFO("Segment %s reloaded, shared mode.\n",
-                          dev_info->segment_name);
        } else if (inbuf[0] == '0') {
                // reload segment in exclusive mode
-               segment_unload(dev_info->segment_name);
-               rc = segment_load(dev_info->segment_name, SEGMENT_EXCLUSIVE_RW,
-                                       &dev_info->start, &dev_info->end);
+               if (dev_info->segment_type == SEG_TYPE_SC) {
+                       PRINT_ERR("Segment type SC (%s) cannot be loaded in "
+                                 "non-shared mode\n", dev_info->segment_name);
+                       rc = -EINVAL;
+                       goto out;
+               }
+               rc = segment_modify_shared(dev_info->segment_name,
+                                          SEGMENT_EXCLUSIVE);
                if (rc < 0) {
-                       PRINT_ERR("Segment %s not reloaded, rc=%d\n",
-                                       dev_info->segment_name, rc);
-                       goto removeseg;
+                       BUG_ON(rc == -EINVAL);
+                       if (rc == -EIO || rc == -ENOENT)
+                               goto removeseg;
+               } else {
+                       dev_info->is_shared = 0;
+                       set_disk_ro(dev_info->gd, 0);
                }
-               dev_info->is_shared = 0;
-               PRINT_INFO("Segment %s reloaded, exclusive (read-write) mode.\n",
-                          dev_info->segment_name);
        } else {
-               up_write(&dcssblk_devices_sem);
                PRINT_WARN("Invalid value, must be 0 or 1\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto out;
        }
-       dev_info->segment_type = rc;
        rc = count;
-
-       switch (dev_info->segment_type) {
-               case SEGMENT_SHARED_RO:
-               case SEGMENT_EXCLUSIVE_RO:
-                       set_disk_ro(dev_info->gd, 1);
-                       break;
-               case SEGMENT_SHARED_RW:
-               case SEGMENT_EXCLUSIVE_RW:
-                       set_disk_ro(dev_info->gd, 0);
-                       break;
-       }
-       if ((inbuf[0] == '1') &&
-          ((dev_info->segment_type == SEGMENT_EXCLUSIVE_RO) ||
-           (dev_info->segment_type == SEGMENT_EXCLUSIVE_RW))) {
-               PRINT_WARN("Could not get shared copy of segment %s\n",
-                               dev_info->segment_name);
-               rc = -EPERM;
-       }
-       if ((inbuf[0] == '0') &&
-          ((dev_info->segment_type == SEGMENT_SHARED_RO) ||
-           (dev_info->segment_type == SEGMENT_SHARED_RW))) {
-               PRINT_WARN("Could not get exclusive copy of segment %s\n",
-                               dev_info->segment_name);
-               rc = -EPERM;
-       }
-       up_write(&dcssblk_devices_sem);
        goto out;
 
 removeseg:
@@ -254,8 +275,8 @@ removeseg:
        put_disk(dev_info->gd);
        device_unregister(dev);
        put_device(dev);
-       up_write(&dcssblk_devices_sem);
 out:
+       up_write(&dcssblk_devices_sem);
        return rc;
 }
 
@@ -292,7 +313,7 @@ dcssblk_save_store(struct device *dev, const char *inbuf, size_t count)
                        // device is idle => we save immediately
                        PRINT_INFO("Saving segment %s\n",
                                   dev_info->segment_name);
-                       segment_replace(dev_info->segment_name);
+                       segment_save(dev_info->segment_name);
                }  else {
                        // device is busy => we save it when it becomes
                        // idle in dcssblk_release
@@ -390,18 +411,17 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count)
        /*
         * load the segment
         */
-       rc = segment_load(local_buf, SEGMENT_SHARED_RO,
+       rc = segment_load(local_buf, SEGMENT_SHARED,
                                &dev_info->start, &dev_info->end);
        if (rc < 0) {
-               PRINT_ERR("Segment %s not loaded, rc=%d\n", local_buf, rc);
+               dcssblk_segment_warn(rc, dev_info->segment_name);
                goto dealloc_gendisk;
        }
        seg_byte_size = (dev_info->end - dev_info->start + 1);
        set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
-       PRINT_INFO("Loaded segment %s from %p to %p, size = %lu Byte, "
-                  "capacity = %lu sectors (512 Byte)\n", local_buf,
-                       (void *) dev_info->start, (void *) dev_info->end,
-                       seg_byte_size, seg_byte_size >> 9);
+       PRINT_INFO("Loaded segment %s, size = %lu Byte, "
+                  "capacity = %lu (512 Byte) sectors\n", local_buf,
+                  seg_byte_size, seg_byte_size >> 9);
 
        dev_info->segment_type = rc;
        dev_info->save_pending = 0;
@@ -451,12 +471,12 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count)
        blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
 
        switch (dev_info->segment_type) {
-               case SEGMENT_SHARED_RO:
-               case SEGMENT_EXCLUSIVE_RO:
+               case SEG_TYPE_SR:
+               case SEG_TYPE_ER:
+               case SEG_TYPE_SC:
                        set_disk_ro(dev_info->gd,1);
                        break;
-               case SEGMENT_SHARED_RW:
-               case SEGMENT_EXCLUSIVE_RW:
+               default:
                        set_disk_ro(dev_info->gd,0);
                        break;
        }
@@ -589,7 +609,7 @@ dcssblk_release(struct inode *inode, struct file *filp)
            && (dev_info->save_pending)) {
                PRINT_INFO("Segment %s became idle and is being saved now\n",
                            dev_info->segment_name);
-               segment_replace(dev_info->segment_name);
+               segment_save(dev_info->segment_name);
                dev_info->save_pending = 0;
        }
        up_write(&dcssblk_devices_sem);
index 312057e..d428c90 100644 (file)
@@ -74,10 +74,9 @@ static int xpram_devs;
  */
 static int devs = XPRAM_DEVS;
 static unsigned int sizes[XPRAM_MAX_DEVS];
-static unsigned int sizes_count;
 
 module_param(devs, int, 0);
-module_param_array(sizes, int, sizes_count, 0);
+module_param_array(sizes, int, NULL, 0);
 
 MODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \
                 "the default is " __MODULE_STRING(XPRAM_DEVS) "\n");
index 9c72ffb..e74554b 100644 (file)
@@ -983,35 +983,16 @@ tty3215_write_room(struct tty_struct *tty)
  * String write routine for 3215 ttys
  */
 static int
-tty3215_write(struct tty_struct * tty, int from_user,
+tty3215_write(struct tty_struct * tty,
              const unsigned char *buf, int count)
 {
        struct raw3215_info *raw;
-       int length, ret;
 
        if (!tty)
                return 0;
        raw = (struct raw3215_info *) tty->driver_data;
-       if (!from_user) {
-               raw3215_write(raw, buf, count);
-               return count;
-       }
-       ret = 0;
-       while (count > 0) {
-               length = count < 80 ? count : 80;
-               length -= copy_from_user(raw->ubuffer,
-                               (const unsigned char __user *)buf, length);
-               if (length == 0) {
-                       if (!ret)
-                               ret = -EFAULT;
-                       break;
-               }
-               raw3215_write(raw, raw->ubuffer, count);
-               buf += length;
-               count -= length;
-               ret += length;
-       }
-       return ret;
+       raw3215_write(raw, buf, count);
+       return count;
 }
 
 /*
index 11c1b3b..77cbe9c 100644 (file)
@@ -73,14 +73,11 @@ void
 con3270_set_timer(struct con3270 *cp, int expires)
 {
        if (expires == 0) {
-               if (timer_pending(&cp->timer))
-                       del_timer(&cp->timer);
+               del_timer(&cp->timer);
                return;
        }
-       if (timer_pending(&cp->timer)) {
-               if (mod_timer(&cp->timer, jiffies + expires))
-                       return;
-       }
+       if (mod_timer(&cp->timer, jiffies + expires))
+               return;
        cp->timer.function = (void (*)(unsigned long)) con3270_update;
        cp->timer.data = (unsigned long) cp;
        cp->timer.expires = jiffies + expires;
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");
index cd11cb1..3491615 100644 (file)
@@ -395,36 +395,14 @@ sclp_tty_write_string(const unsigned char *str, int count)
  * routine will return the number of characters actually accepted for writing.
  */
 static int
-sclp_tty_write(struct tty_struct *tty, int from_user,
-              const unsigned char *buf, int count)
+sclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
-       int length, ret;
-
        if (sclp_tty_chars_count > 0) {
                sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
                sclp_tty_chars_count = 0;
        }
-       if (!from_user) {
-               sclp_tty_write_string(buf, count);
-               return count;
-       }
-       ret = 0;
-       while (count > 0) {
-               length = count < SCLP_TTY_BUF_SIZE ?
-                       count : SCLP_TTY_BUF_SIZE;
-               length -= copy_from_user(sclp_tty_chars,
-                               (const unsigned char __user *)buf, length);
-               if (length == 0) {
-                       if (!ret)
-                               ret = -EFAULT;
-                       break;
-               }
-               sclp_tty_write_string(sclp_tty_chars, length);
-               buf += length;
-               count -= length;
-               ret += length;
-       }
-       return ret;
+       sclp_tty_write_string(buf, count);
+       return count;
 }
 
 /*
@@ -623,7 +601,7 @@ sclp_get_input(unsigned char *start, unsigned char *end)
 
        /* if set in ioctl write operators input to console  */
        if (sclp_ioctls.echo)
-               sclp_tty_write(sclp_tty, 0, start, count);
+               sclp_tty_write(sclp_tty, start, count);
 
        /* transfer input to high level driver */
        sclp_tty_input(start, count);
index cc143fa..69aed79 100644 (file)
@@ -473,33 +473,9 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
  * number of characters actually accepted for writing.
  */
 static int
-sclp_vt220_write(struct tty_struct *tty, int from_user,
-                const unsigned char *buf, int count)
+sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
-       int length;
-       int ret;
-
-       if (!from_user)
-               return __sclp_vt220_write(buf, count, 1, 0);
-       /* Use intermediate buffer to prevent calling copy_from_user() while
-        * holding a lock. */
-       ret = 0;
-       while (count > 0) {
-               length = count < SCLP_VT220_BUF_SIZE ?
-                        count : SCLP_VT220_BUF_SIZE;
-               length -= copy_from_user(tty->driver_data,
-                               (const unsigned char __user *)buf, length);
-               if (length == 0) {
-                       if (!ret)
-                               return -EFAULT;
-                       break;
-               }
-               length = __sclp_vt220_write(tty->driver_data, length, 1, 0);
-               buf += length;
-               count -= length;
-               ret += length;
-       }
-       return ret;
+       return __sclp_vt220_write(buf, count, 1, 0);
 }
 
 #define SCLP_VT220_SESSION_ENDED       0x01
index b7f4e7b..1efc9f2 100644 (file)
@@ -225,8 +225,8 @@ tapeblock_setup_device(struct tape_device * device)
        if (!blkdat->request_queue)
                return -ENOMEM;
 
-       elevator_exit(blkdat->request_queue);
-       rc = elevator_init(blkdat->request_queue, &elevator_noop);
+       elevator_exit(blkdat->request_queue->elevator);
+       rc = elevator_init(blkdat->request_queue, "noop");
        if (rc)
                goto cleanup_queue;
 
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);
index b834e6a..8ab01af 100644 (file)
@@ -66,6 +66,7 @@ struct senseid {
 struct ccw_device_private {
        int state;              /* device state */
        atomic_t onoff;
+       unsigned long registered;
        __u16 devno;            /* device number */
        __u16 irq;              /* subchannel number */
        __u8 imask;             /* lpm mask for SNID/SID/SPGID */
@@ -137,6 +138,9 @@ void device_trigger_reprobe(struct subchannel *);
 /* Helper functions for vary on/off. */
 void device_set_waiting(struct subchannel *);
 
+/* Machine check helper function. */
+void device_kill_pending_timer(struct subchannel *);
+
 /* Helper functions to build lists for the slow path. */
 int css_enqueue_subchannel_slow(unsigned long schid);
 void css_walk_subchannel_slow_list(void (*fn)(unsigned long));
index ea15f86..15edebb 100644 (file)
@@ -1,5 +1,5 @@
 #
-# S/390 miscellaneous devices
+# S/390 crypto devices
 #
 
 z90crypt-objs := z90main.o z90hardware.o
index 624ef6a..bcabac7 100644 (file)
@@ -1,11 +1,11 @@
 /*
- *  linux/drivers/s390/misc/z90common.h
+ *  linux/drivers/s390/crypto/z90common.h
  *
- *  z90crypt 1.3.1
+ *  z90crypt 1.3.2
  *
  *  Copyright (C)  2001, 2004 IBM Corporation
  *  Author(s): Robert Burroughs (burrough@us.ibm.com)
- *            Eric Rossman (edrossma@us.ibm.com)
+ *             Eric Rossman (edrossma@us.ibm.com)
  *
  *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  *
@@ -16,7 +16,7 @@
  *
  * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifndef _Z90COMMON_
-#define _Z90COMMON_
+#ifndef _Z90COMMON_H_
+#define _Z90COMMON_H_
 
-#define VERSION_Z90COMMON_H "$Revision: 1.8 $"
+#define VERSION_Z90COMMON_H "$Revision: 1.16 $"
 
 
 #define RESPBUFFSIZE 256
 #define PCI_FUNC_KEY_DECRYPT 0x5044
 #define PCI_FUNC_KEY_ENCRYPT 0x504B
+extern int ext_bitlens;
 
 enum devstat {
        DEV_GONE,
@@ -56,6 +57,7 @@ enum hdstat {
        HD_TSQ_EXCEPTION
 };
 
+#define Z90C_NO_DEVICES                1
 #define Z90C_AMBIGUOUS_DOMAIN  2
 #define Z90C_INCORRECT_DOMAIN  3
 #define ENOTINIT               4
@@ -74,13 +76,13 @@ enum hdstat {
 #define REC_OPERAND_SIZE 9
 #define REC_EVEN_MOD   10
 #define REC_NO_WORK    11
-#define REC_HARDWAR_ERR 12
-#define REC_NO_RESPONSE 13
+#define REC_HARDWAR_ERR        12
+#define REC_NO_RESPONSE        13
 #define REC_RETRY_DEV  14
 #define REC_USER_GONE  15
-#define REC_BAD_MESSAGE 16
-#define REC_INVALID_PAD 17
-#define REC_RELEASED   28
+#define REC_BAD_MESSAGE        16
+#define REC_INVALID_PAD        17
+#define REC_USE_PCICA  18
 
 #define WRONG_DEVICE_TYPE 20
 
@@ -89,18 +91,55 @@ enum hdstat {
 #define TSQ_FATAL_ERROR 34
 #define RSQ_FATAL_ERROR 35
 
-#define PCICA  0
-#define PCICC  1
-#define PCIXCC 2
-#define NILDEV -1
-#define ANYDEV -1
+#define Z90CRYPT_NUM_TYPES     5
+#define PCICA          0
+#define PCICC          1
+#define PCIXCC_MCL2    2
+#define PCIXCC_MCL3    3
+#define CEX2C          4
+#define NILDEV         -1
+#define ANYDEV         -1
+#define PCIXCC_UNK     -2
 
 enum hdevice_type {
        PCICC_HW  = 3,
        PCICA_HW  = 4,
        PCIXCC_HW = 5,
        OTHER_HW  = 6,
-       OTHER2_HW = 7
+       CEX2C_HW  = 7
+};
+
+struct CPRBX {
+       unsigned short cprb_len;
+       unsigned char  cprb_ver_id;
+       unsigned char  pad_000[3];
+       unsigned char  func_id[2];
+       unsigned char  cprb_flags[4];
+       unsigned int   req_parml;
+       unsigned int   req_datal;
+       unsigned int   rpl_msgbl;
+       unsigned int   rpld_parml;
+       unsigned int   rpl_datal;
+       unsigned int   rpld_datal;
+       unsigned int   req_extbl;
+       unsigned char  pad_001[4];
+       unsigned int   rpld_extbl;
+       unsigned char  req_parmb[16];
+       unsigned char  req_datab[16];
+       unsigned char  rpl_parmb[16];
+       unsigned char  rpl_datab[16];
+       unsigned char  req_extb[16];
+       unsigned char  rpl_extb[16];
+       unsigned short ccp_rtcode;
+       unsigned short ccp_rscode;
+       unsigned int   mac_data_len;
+       unsigned char  logon_id[8];
+       unsigned char  mac_value[8];
+       unsigned char  mac_content_flgs;
+       unsigned char  pad_002;
+       unsigned short domain;
+       unsigned char  pad_003[12];
+       unsigned char  pad_004[36];
 };
 
 #ifndef DEV_NAME
index dbc5dd0..82a1d97 100644 (file)
@@ -1,11 +1,11 @@
 /*
- *  linux/drivers/s390/misc/z90crypt.h
+ *  linux/drivers/s390/crypto/z90crypt.h
  *
- *  z90crypt 1.3.1
+ *  z90crypt 1.3.2
  *
  *  Copyright (C)  2001, 2004 IBM Corporation
  *  Author(s): Robert Burroughs (burrough@us.ibm.com)
- *            Eric Rossman (edrossma@us.ibm.com)
+ *             Eric Rossman (edrossma@us.ibm.com)
  *
  *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  *
@@ -16,7 +16,7 @@
  *
  * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifndef _LINUX_Z90CRYPT_H_
-#define _LINUX_Z90CRYPT_H_
+#ifndef _Z90CRYPT_H_
+#define _Z90CRYPT_H_
 
 #include <linux/ioctl.h>
 
-#define VERSION_Z90CRYPT_H "$Revision: 1.2 $"
+#define VERSION_Z90CRYPT_H "$Revision: 1.11 $"
 
 #define z90crypt_VERSION 1
 #define z90crypt_RELEASE 3     // 2 = PCIXCC, 3 = rewrite for coding standards
-#define z90crypt_VARIANT 1
+#define z90crypt_VARIANT 2     // 2 = added PCIXCC MCL3 and CEX2C support
+
+/**
+ * If we are not using the sparse checker, __user has no use.
+ */
+#ifdef __CHECKER__
+# define __user                __attribute__((noderef, address_space(1)))
+#else
+# define __user
+#endif
 
 /**
  * struct ica_rsa_modexpo
@@ -93,16 +102,16 @@ struct ica_rsa_modexpo_crt {
  *     This takes an ica_rsa_modexpo struct as its arg.
  *
  *     NOTE: please refer to the comments preceding this structure
- *          for the implementation details for the contents of the
- *          block
+ *           for the implementation details for the contents of the
+ *           block
  *
  *   ICARSACRT
  *     Perform an RSA operation using a Chinese-Remainder Theorem key
  *     This takes an ica_rsa_modexpo_crt struct as its arg.
  *
  *     NOTE: please refer to the comments preceding this structure
- *          for the implementation details for the contents of the
- *          block
+ *           for the implementation details for the contents of the
+ *           block
  *
  *   Z90STAT_TOTALCOUNT
  *     Return an integer count of all device types together.
@@ -113,8 +122,14 @@ struct ica_rsa_modexpo_crt {
  *   Z90STAT_PCICCCOUNT
  *     Return an integer count of all PCICCs.
  *
- *   Z90STAT_PCIXCCCOUNT
- *     Return an integer count of all PCIXCCs.
+ *   Z90STAT_PCIXCCMCL2COUNT
+ *     Return an integer count of all MCL2 PCIXCCs.
+ *
+ *   Z90STAT_PCIXCCMCL3COUNT
+ *     Return an integer count of all MCL3 PCIXCCs.
+ *
+ *   Z90STAT_CEX2CCOUNT
+ *     Return an integer count of all CEX2Cs.
  *
  *   Z90STAT_REQUESTQ_COUNT
  *     Return an integer count of the number of entries waiting to be
@@ -133,10 +148,12 @@ struct ica_rsa_modexpo_crt {
  *   Z90STAT_STATUS_MASK
  *     Return an 64 element array of unsigned chars for the status of
  *     all devices.
- *      0x01: PCICA
- *      0x02: PCICC
- *      0x03: PCIXCC
- *      0x0d: device is disabled via the proc filesystem
+ *       0x01: PCICA
+ *       0x02: PCICC
+ *       0x03: PCIXCC_MCL2
+ *       0x04: PCIXCC_MCL3
+ *       0x05: CEX2C
+ *       0x0d: device is disabled via the proc filesystem
  *
  *   Z90STAT_QDEPTH_MASK
  *     Return an 64 element array of unsigned chars for the queue
@@ -152,18 +169,23 @@ struct ica_rsa_modexpo_crt {
  *     This takes an ica_z90_status struct as its arg.
  *
  *     NOTE: this ioctl() is deprecated, and has been replaced with
- *          single ioctl()s for each type of status being requested
+ *           single ioctl()s for each type of status being requested
+ *
+ *   Z90STAT_PCIXCCCOUNT (deprecated)
+ *     Return an integer count of all PCIXCCs (MCL2 + MCL3).
+ *     This is DEPRECATED now that MCL3 PCIXCCs are treated differently from
+ *     MCL2 PCIXCCs.
  *
  *   Z90QUIESCE (not recommended)
  *     Quiesce the driver.  This is intended to stop all new
- *     requests from being processed.  Its use is not recommended,
+ *     requests from being processed.  Its use is NOT recommended,
  *     except in circumstances where there is no other way to stop
  *     callers from accessing the driver.  Its original use was to
  *     allow the driver to be "drained" of work in preparation for
  *     a system shutdown.
  *
  *     NOTE: once issued, this ban on new work cannot be undone
- *          except by unloading and reloading the driver.
+ *           except by unloading and reloading the driver.
  */
 
 /**
@@ -172,8 +194,9 @@ struct ica_rsa_modexpo_crt {
 #define ICARSAMODEXPO  _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x05, 0)
 #define ICARSACRT      _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x06, 0)
 
-/* DEPRECATED status call (bound for removal SOON) */
+/* DEPRECATED status calls (bound for removal at some point) */
 #define ICAZ90STATUS   _IOR(Z90_IOCTL_MAGIC, 0x10, struct ica_z90_status)
+#define Z90STAT_PCIXCCCOUNT    _IOR(Z90_IOCTL_MAGIC, 0x43, int)
 
 /* unrelated to ICA callers */
 #define Z90QUIESCE     _IO(Z90_IOCTL_MAGIC, 0x11)
@@ -182,7 +205,9 @@ struct ica_rsa_modexpo_crt {
 #define Z90STAT_TOTALCOUNT     _IOR(Z90_IOCTL_MAGIC, 0x40, int)
 #define Z90STAT_PCICACOUNT     _IOR(Z90_IOCTL_MAGIC, 0x41, int)
 #define Z90STAT_PCICCCOUNT     _IOR(Z90_IOCTL_MAGIC, 0x42, int)
-#define Z90STAT_PCIXCCCOUNT    _IOR(Z90_IOCTL_MAGIC, 0x43, int)
+#define Z90STAT_PCIXCCMCL2COUNT        _IOR(Z90_IOCTL_MAGIC, 0x4b, int)
+#define Z90STAT_PCIXCCMCL3COUNT        _IOR(Z90_IOCTL_MAGIC, 0x4c, int)
+#define Z90STAT_CEX2CCOUNT     _IOR(Z90_IOCTL_MAGIC, 0x4d, int)
 #define Z90STAT_REQUESTQ_COUNT _IOR(Z90_IOCTL_MAGIC, 0x44, int)
 #define Z90STAT_PENDINGQ_COUNT _IOR(Z90_IOCTL_MAGIC, 0x45, int)
 #define Z90STAT_TOTALOPEN_COUNT _IOR(Z90_IOCTL_MAGIC, 0x46, int)
@@ -199,8 +224,9 @@ struct ica_rsa_modexpo_crt {
 #define ERELEASED 131  // user released while ioctl pending
 #define EQUIESCE  132  // z90crypt quiescing (no more work allowed)
 #define ETIMEOUT  133  // request timed out
-#define EUNKNOWN  134  // some unrecognized error occured
-#define EGETBUFF  135  // Error getting buffer
+#define EUNKNOWN  134  // some unrecognized error occured (retry may succeed)
+#define EGETBUFF  135  // Error getting buffer or hardware lacks capability
+                       // (retry in software)
 
 /**
  * DEPRECATED STRUCTURES
@@ -222,10 +248,11 @@ struct ica_z90_status {
        int pendingqWaitCount;
        int totalOpenCount;
        int cryptoDomain;
-       // status: 0=not there. 1=PCICA. 2=PCICC. 3=PCIXCC
+       // status: 0=not there, 1=PCICA, 2=PCICC, 3=PCIXCC_MCL2, 4=PCIXCC_MCL3,
+       //         5=CEX2C
        unsigned char status[MASK_LENGTH];
        // qdepth: # work elements waiting for each device
        unsigned char qdepth[MASK_LENGTH];
 };
 
-#endif /* _LINUX_Z90CRYPT_H_ */
+#endif /* _Z90CRYPT_H_ */
index 8c8db43..beb6a5e 100644 (file)
@@ -1,11 +1,11 @@
 /*
- *  linux/drivers/s390/misc/z90hardware.c
+ *  linux/drivers/s390/crypto/z90hardware.c
  *
- *  z90crypt 1.3.1
+ *  z90crypt 1.3.2
  *
  *  Copyright (C)  2001, 2004 IBM Corporation
  *  Author(s): Robert Burroughs (burrough@us.ibm.com)
- *            Eric Rossman (edrossma@us.ibm.com)
+ *             Eric Rossman (edrossma@us.ibm.com)
  *
  *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  *
@@ -16,7 +16,7 @@
  *
  * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
@@ -32,9 +32,9 @@
 #include "z90crypt.h"
 #include "z90common.h"
 
-#define VERSION_Z90HARDWARE_C "$Revision: 1.19 $"
+#define VERSION_Z90HARDWARE_C "$Revision: 1.33 $"
 
-char z90chardware_version[] __initdata =
+char z90hardware_version[] __initdata =
        "z90hardware.o (" VERSION_Z90HARDWARE_C "/"
                          VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")";
 
@@ -224,7 +224,7 @@ struct type6_hdr {
        unsigned char right[4];
        unsigned char reserved3[2];
        unsigned char reserved4[2];
-       unsigned char pfs[4];
+       unsigned char apfs[4];
        unsigned int  offset1;
        unsigned int  offset2;
        unsigned int  offset3;
@@ -278,39 +278,6 @@ struct CPRB {
        unsigned char svr_name[8];
 };
 
-struct CPRBX {
-       unsigned short cprb_len;
-       unsigned char  cprb_ver_id;
-       unsigned char  pad_000[3];
-       unsigned char  func_id[2];
-       unsigned char  cprb_flags[4];
-       unsigned int   req_parml;
-       unsigned int   req_datal;
-       unsigned int   rpl_msgbl;
-       unsigned int   rpld_parml;
-       unsigned int   rpl_datal;
-       unsigned int   rpld_datal;
-       unsigned int   req_extbl;
-       unsigned char  pad_001[4];
-       unsigned int   rpld_extbl;
-       unsigned char  req_parmb[16];
-       unsigned char  req_datab[16];
-       unsigned char  rpl_parmb[16];
-       unsigned char  rpl_datab[16];
-       unsigned char  req_extb[16];
-       unsigned char  rpl_extb[16];
-       unsigned short ccp_rtcode;
-       unsigned short ccp_rscode;
-       unsigned int   mac_data_len;
-       unsigned char  logon_id[8];
-       unsigned char  mac_value[8];
-       unsigned char  mac_content_flgs;
-       unsigned char  pad_002;
-       unsigned short domain;
-       unsigned char  pad_003[12];
-       unsigned char  pad_004[36];
-};
-
 struct type6_msg {
        struct type6_hdr header;
        struct CPRB      CPRB;
@@ -347,12 +314,13 @@ struct type82_hdr {
 #define REPLY_ERROR_FORMAT_FIELD     0x29
 #define REPLY_ERROR_INVALID_COMMAND  0x30
 #define REPLY_ERROR_MALFORMED_MSG    0x40
-#define REPLY_ERROR_RESERVED_FIELD   0x50
+#define REPLY_ERROR_RESERVED_FIELDO  0x50
 #define REPLY_ERROR_WORD_ALIGNMENT   0x60
 #define REPLY_ERROR_MESSAGE_LENGTH   0x80
 #define REPLY_ERROR_OPERAND_INVALID  0x82
 #define REPLY_ERROR_OPERAND_SIZE     0x84
 #define REPLY_ERROR_EVEN_MOD_IN_OPND 0x85
+#define REPLY_ERROR_RESERVED_FIELD   0x88
 #define REPLY_ERROR_TRANSPORT_FAIL   0x90
 #define REPLY_ERROR_PACKET_TRUNCATED 0xA0
 #define REPLY_ERROR_ZERO_BUFFER_LEN  0xB0
@@ -379,7 +347,7 @@ struct type86_fmt2_msg {
        unsigned int      offset2;
        unsigned int      count3;
        unsigned int      offset3;
-       unsigned int      ount4;
+       unsigned int      count4;
        unsigned int      offset4;
 };
 
@@ -546,18 +514,30 @@ static struct CPRBX static_cprbx = {
         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-static struct function_and_rules_block static_pkd_function_and_rulesX = {
+static struct function_and_rules_block static_pkd_function_and_rulesX_MCL2 = {
        {0x50,0x44},
        {0x00,0x0A},
        {'P','K','C','S','-','1','.','2'}
 };
 
-static struct function_and_rules_block static_pke_function_and_rulesX = {
+static struct function_and_rules_block static_pke_function_and_rulesX_MCL2 = {
        {0x50,0x4B},
        {0x00,0x0A},
        {'Z','E','R','O','-','P','A','D'}
 };
 
+static struct function_and_rules_block static_pkd_function_and_rulesX = {
+       {0x50,0x44},
+       {0x00,0x0A},
+       {'Z','E','R','O','-','P','A','D'}
+};
+
+static struct function_and_rules_block static_pke_function_and_rulesX = {
+       {0x50,0x4B},
+       {0x00,0x0A},
+       {'M','R','P',' ',' ',' ',' ',' '}
+};
+
 struct T6_keyBlock_hdrX {
        unsigned short blen;
        unsigned short ulen;
@@ -701,11 +681,9 @@ static struct cca_public_sec static_cca_pub_sec = {
 
 #define FIXED_TYPE6_CR_LENX 0x000001E3
 
-#ifndef MAX_RESPONSE_SIZE
 #define MAX_RESPONSE_SIZE 0x00000710
 
 #define MAX_RESPONSEX_SIZE 0x0000077C
-#endif
 
 #define RESPONSE_CPRB_SIZE  0x000006B8
 #define RESPONSE_CPRBX_SIZE 0x00000724
@@ -1063,7 +1041,6 @@ query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
                        *q_depth = t_depth + 1;
                        switch (t_dev_type) {
                        case OTHER_HW:
-                       case OTHER2_HW:
                                stat = HD_NOT_THERE;
                                *dev_type = NILDEV;
                                break;
@@ -1074,7 +1051,10 @@ query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
                                *dev_type = PCICC;
                                break;
                        case PCIXCC_HW:
-                               *dev_type = PCIXCC;
+                               *dev_type = PCIXCC_UNK;
+                               break;
+                       case CEX2C_HW:
+                               *dev_type = CEX2C;
                                break;
                        default:
                                *dev_type = NILDEV;
@@ -1133,6 +1113,7 @@ query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
                default:
                        stat = HD_NOT_THERE;
                        break_out = 1;
+                       break;
                }
                if (break_out)
                        break;
@@ -1170,18 +1151,11 @@ reset_device(int deviceNr, int cdx, int resetNr)
                        switch (stat_word.response_code) {
                        case AP_RESPONSE_NORMAL:
                                stat = DEV_ONLINE;
-                               if (stat_word.q_stat_flags &
-                                   AP_Q_STATUS_EMPTY)
+                               if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
                                        break_out = 1;
                                break;
                        case AP_RESPONSE_Q_NOT_AVAIL:
-                               stat = DEV_GONE;
-                               break_out = 1;
-                               break;
                        case AP_RESPONSE_DECONFIGURED:
-                               stat = DEV_GONE;
-                               break_out = 1;
-                               break;
                        case AP_RESPONSE_CHECKSTOPPED:
                                stat = DEV_GONE;
                                break_out = 1;
@@ -1195,6 +1169,7 @@ reset_device(int deviceNr, int cdx, int resetNr)
                default:
                        stat = DEV_GONE;
                        break_out = 1;
+                       break;
                }
                if (break_out == 1)
                        break;
@@ -1251,7 +1226,7 @@ send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
               msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3],
               msg_ext[4], msg_ext[5], msg_ext[6], msg_ext[7],
               msg_ext[8], msg_ext[9], msg_ext[10], msg_ext[11]);
-       print_buffer(msg_ext+12, msg_len);
+       print_buffer(msg_ext+CALLER_HEADER, msg_len);
 #endif
 
        ccode = sen(msg_len, msg_ext, &stat_word);
@@ -1283,14 +1258,15 @@ send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
                break;
        default:
                stat = DEV_GONE;
+               break;
        }
 
        return stat;
 }
 
 enum devstat
-receive_from_AP(int dev_nr, int cdx, int resplen,
-               unsigned char *resp, unsigned char *psmid)
+receive_from_AP(int dev_nr, int cdx, int resplen, unsigned char *resp,
+               unsigned char *psmid)
 {
        int ccode;
        struct ap_status_word stat_word;
@@ -1543,6 +1519,7 @@ ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        struct type6_hdr *tp6Hdr_p;
        struct CPRB *cprb_p;
        struct cca_private_ext_ME *key_p;
+       static int deprecated_msg_count = 0;
 
        mod_len = icaMsg_p->inputdatalength;
        tmp_size = FIXED_TYPE6_ME_LEN + mod_len;
@@ -1593,13 +1570,19 @@ ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
                return SEN_USER_ERROR;
 
        if (is_common_public_key(temp, mod_len)) {
-               PRINTK("Common public key used for modex decrypt\n");
+               if (deprecated_msg_count < 20) {
+                       PRINTK("Common public key used for modex decrypt\n");
+                       deprecated_msg_count++;
+                       if (deprecated_msg_count == 20)
+                               PRINTK("No longer issuing messages about common"
+                                      " public key for modex decrypt.\n");
+               }
                return SEN_NOT_AVAIL;
        }
 
        temp = key_p->pvtMESec.modulus + sizeof(key_p->pvtMESec.modulus)
               - mod_len;
-       if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len) != 0)
+       if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
                return SEN_RELEASED;
        if (is_empty(temp, mod_len))
                return SEN_USER_ERROR;
@@ -1617,24 +1600,33 @@ ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
 {
        int mod_len, vud_len, exp_len, key_len;
        int pad_len, tmp_size, total_CPRB_len, parmBlock_l, i;
-       unsigned char temp_exp[256], *exp_p, *temp;
+       unsigned char *temp_exp, *exp_p, *temp;
        struct type6_hdr *tp6Hdr_p;
        struct CPRB *cprb_p;
        struct cca_public_key *key_p;
        struct T6_keyBlock_hdr *keyb_p;
 
+       temp_exp = kmalloc(256, GFP_KERNEL);
+       if (!temp_exp)
+               return EGETBUFF;
        mod_len = icaMsg_p->inputdatalength;
-       if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
+       if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
+               kfree(temp_exp);
                return SEN_RELEASED;
-       if (is_empty(temp_exp, mod_len))
+       }
+       if (is_empty(temp_exp, mod_len)) {
+               kfree(temp_exp);
                return SEN_USER_ERROR;
+       }
 
        exp_p = temp_exp;
        for (i = 0; i < mod_len; i++)
                if (exp_p[i])
                        break;
-       if (i >= mod_len)
+       if (i >= mod_len) {
+               kfree(temp_exp);
                return SEN_USER_ERROR;
+       }
 
        exp_len = mod_len - i;
        exp_p += i;
@@ -1665,17 +1657,25 @@ ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
                 sizeof(struct function_and_rules_block));
        temp += sizeof(struct function_and_rules_block);
        temp += 2;
-       if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
+       if (copy_from_user(temp, icaMsg_p->inputdata, mod_len)) {
+               kfree(temp_exp);
                return SEN_RELEASED;
-       if (is_empty(temp, mod_len))
+       }
+       if (is_empty(temp, mod_len)) {
+               kfree(temp_exp);
                return SEN_USER_ERROR;
-       if (temp[0] != 0x00 || temp[1] != 0x02)
+       }
+       if ((temp[0] != 0x00) || (temp[1] != 0x02)) {
+               kfree(temp_exp);
                return SEN_NOT_AVAIL;
+       }
        for (i = 2; i < mod_len; i++)
                if (temp[i] == 0x00)
                        break;
-       if ((i < 9) || (i > (mod_len - 2)))
+       if ((i < 9) || (i > (mod_len - 2))) {
+               kfree(temp_exp);
                return SEN_NOT_AVAIL;
+       }
        pad_len = i + 1;
        vud_len = mod_len - pad_len;
        memmove(temp, temp+pad_len, vud_len);
@@ -1689,6 +1689,7 @@ ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        key_p = (struct cca_public_key *)temp;
        temp = key_p->pubSec.exponent;
        memcpy(temp, exp_p, exp_len);
+       kfree(temp_exp);
        temp += exp_len;
        if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
                return SEN_RELEASED;
@@ -1697,7 +1698,7 @@ ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        key_p->pubSec.modulus_bit_len = 8 * mod_len;
        key_p->pubSec.modulus_byte_len = mod_len;
        key_p->pubSec.exponent_len = exp_len;
-       key_p->pubSec.section_length = 12 + mod_len + exp_len;
+       key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
        key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
        key_p->pubHdr.token_length = key_len;
        key_len += 4;
@@ -1824,27 +1825,37 @@ ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
 
 static int
 ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
-                           int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+                           int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
+                           int dev_type)
 {
        int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
        int key_len, i;
-       unsigned char temp_exp[256], *tgt_p, *temp, *exp_p;
+       unsigned char *temp_exp, *tgt_p, *temp, *exp_p;
        struct type6_hdr *tp6Hdr_p;
        struct CPRBX *cprbx_p;
        struct cca_public_key *key_p;
        struct T6_keyBlock_hdrX *keyb_p;
 
+       temp_exp = kmalloc(256, GFP_KERNEL);
+       if (!temp_exp)
+               return EGETBUFF;
        mod_len = icaMsg_p->inputdatalength;
-       if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
+       if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
+               kfree(temp_exp);
                return SEN_RELEASED;
-       if (is_empty(temp_exp, mod_len))
+       }
+       if (is_empty(temp_exp, mod_len)) {
+               kfree(temp_exp);
                return SEN_USER_ERROR;
+       }
        exp_p = temp_exp;
        for (i = 0; i < mod_len; i++)
                if (exp_p[i])
                        break;
-       if (i >= mod_len)
+       if (i >= mod_len) {
+               kfree(temp_exp);
                return SEN_USER_ERROR;
+       }
        exp_len = mod_len - i;
        exp_p += i;
        PDEBUG("exp_len after computation: %08x\n", exp_len);
@@ -1867,15 +1878,23 @@ ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        cprbx_p->domain = (unsigned short)cdx;
        cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE;
        tgt_p += sizeof(struct CPRBX);
-       memcpy(tgt_p, &static_pke_function_and_rulesX,
-              sizeof(struct function_and_rules_block));
+       if (dev_type == PCIXCC_MCL2)
+               memcpy(tgt_p, &static_pke_function_and_rulesX_MCL2,
+                      sizeof(struct function_and_rules_block));
+       else
+               memcpy(tgt_p, &static_pke_function_and_rulesX,
+                      sizeof(struct function_and_rules_block));
        tgt_p += sizeof(struct function_and_rules_block);
 
        tgt_p += 2;
-       if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
-             return SEN_RELEASED;
-       if (is_empty(tgt_p, mod_len))
-             return SEN_USER_ERROR;
+       if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len)) {
+               kfree(temp_exp);
+               return SEN_RELEASED;
+       }
+       if (is_empty(tgt_p, mod_len)) {
+               kfree(temp_exp);
+               return SEN_USER_ERROR;
+       }
        tgt_p -= 2;
        *((short *)tgt_p) = (short) vud_len;
        tgt_p += vud_len;
@@ -1885,15 +1904,16 @@ ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        key_p = (struct cca_public_key *)tgt_p;
        temp = key_p->pubSec.exponent;
        memcpy(temp, exp_p, exp_len);
+       kfree(temp_exp);
        temp += exp_len;
        if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
-             return SEN_RELEASED;
+               return SEN_RELEASED;
        if (is_empty(temp, mod_len))
-             return SEN_USER_ERROR;
+               return SEN_USER_ERROR;
        key_p->pubSec.modulus_bit_len = 8 * mod_len;
        key_p->pubSec.modulus_byte_len = mod_len;
        key_p->pubSec.exponent_len = exp_len;
-       key_p->pubSec.section_length = 12 + mod_len + exp_len;
+       key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
        key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
        key_p->pubHdr.token_length = key_len;
        key_len += 4;
@@ -1908,7 +1928,8 @@ ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
 
 static int
 ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
-                           int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+                           int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
+                           int dev_type)
 {
        int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
        int long_len, pad_len, keyPartsLen, tmp_l;
@@ -1943,8 +1964,12 @@ ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        cprbx_p->req_parml = parmBlock_l;
        cprbx_p->rpl_msgbl = parmBlock_l;
        tgt_p += sizeof(struct CPRBX);
-       memcpy(tgt_p, &static_pkd_function_and_rulesX,
-              sizeof(struct function_and_rules_block));
+       if (dev_type == PCIXCC_MCL2)
+               memcpy(tgt_p, &static_pkd_function_and_rulesX_MCL2,
+                      sizeof(struct function_and_rules_block));
+       else
+               memcpy(tgt_p, &static_pkd_function_and_rulesX,
+                      sizeof(struct function_and_rules_block));
        tgt_p += sizeof(struct function_and_rules_block);
        *((short *)tgt_p) = (short) vud_len;
        tgt_p += 2;
@@ -2043,20 +2068,37 @@ convert_request(unsigned char *buffer, int func, unsigned short function,
                                (struct ica_rsa_modexpo *) buffer,
                                cdx, msg_l_p, (struct type6_msg *) msg_p);
        }
-       if (dev_type == PCIXCC) {
+       if ((dev_type == PCIXCC_MCL2) ||
+           (dev_type == PCIXCC_MCL3) ||
+           (dev_type == CEX2C)) {
                if (func == ICARSACRT)
                        return ICACRT_msg_to_type6CRT_msgX(
                                (struct ica_rsa_modexpo_crt *) buffer,
-                               cdx, msg_l_p, (struct type6_msg *) msg_p);
+                               cdx, msg_l_p, (struct type6_msg *) msg_p,
+                               dev_type);
                else
                        return ICAMEX_msg_to_type6MEX_msgX(
                                (struct ica_rsa_modexpo *) buffer,
-                               cdx, msg_l_p, (struct type6_msg *) msg_p);
+                               cdx, msg_l_p, (struct type6_msg *) msg_p,
+                               dev_type);
        }
 
        return 0;
 }
 
+int ext_bitlens_msg_count = 0;
+static inline void
+unset_ext_bitlens(void)
+{
+       if (!ext_bitlens_msg_count) {
+               PRINTK("Unable to use coprocessors for extended bitlengths. "
+                      "Using PCICAs (if present) for extended bitlengths. "
+                      "This is not an error.\n");
+               ext_bitlens_msg_count++;
+       }
+       ext_bitlens = 0;
+}
+
 int
 convert_response(unsigned char *response, unsigned char *buffer,
                 int *respbufflen_p, unsigned char *resp_buff)
@@ -2064,8 +2106,8 @@ convert_response(unsigned char *response, unsigned char *buffer,
        struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer;
        struct type82_hdr *t82h_p = (struct type82_hdr *) response;
        struct type84_hdr *t84h_p = (struct type84_hdr *) response;
-       struct type86_hdr *t86h_p = (struct type86_hdr *) response;
-       int rv, reply_code, service_rc, service_rs, src_l;
+       struct type86_fmt2_msg *t86m_p =  (struct type86_fmt2_msg *) response;
+       int reply_code, service_rc, service_rs, src_l;
        unsigned char *src_p, *tgt_p;
        struct CPRB *cprb_p;
        struct CPRBX *cprbx_p;
@@ -2075,11 +2117,9 @@ convert_response(unsigned char *response, unsigned char *buffer,
        service_rc = 0;
        service_rs = 0;
        src_l = 0;
-       rv = 0;
        switch (t82h_p->type) {
        case TYPE82_RSP_CODE:
                reply_code = t82h_p->reply_code;
-               rv = 4;
                src_p = (unsigned char *)t82h_p;
                PRINTK("Hardware error: Type 82 Message Header: "
                       "%02x%02x%02x%02x%02x%02x%02x%02x\n",
@@ -2091,15 +2131,9 @@ convert_response(unsigned char *response, unsigned char *buffer,
                src_p = response + (int)t84h_p->len - src_l;
                break;
        case TYPE86_RSP_CODE:
-               reply_code = t86h_p->reply_code;
-               if (t86h_p->format != TYPE86_FMT2) {
-                       rv = 4;
-                       break;
-               }
-               if (reply_code != 0) {
-                       rv = 4;
+               reply_code = t86m_p->hdr.reply_code;
+               if (reply_code != 0)
                        break;
-               }
                cprb_p = (struct CPRB *)
                        (response + sizeof(struct type86_fmt2_msg));
                cprbx_p = (struct CPRBX *) cprb_p;
@@ -2108,11 +2142,22 @@ convert_response(unsigned char *response, unsigned char *buffer,
                        if (service_rc != 0) {
                                le2toI(cprb_p->ccp_rscode, &service_rs);
                                if ((service_rc == 8) && (service_rs == 66))
-                                       PDEBUG("8/66 on PCICC\n");
+                                       PDEBUG("Bad block format on PCICC\n");
+                               else if ((service_rc == 8) && (service_rs == 770)) {
+                                       PDEBUG("Invalid key length on PCICC\n");
+                                       unset_ext_bitlens();
+                                       return REC_USE_PCICA;
+                               }
+                               else if ((service_rc == 8) && (service_rs == 783)) {
+                                       PDEBUG("Extended bitlengths not enabled"
+                                              "on PCICC\n");
+                                       unset_ext_bitlens();
+                                       return REC_USE_PCICA;
+                               }
                                else
                                        PRINTK("service rc/rs: %d/%d\n",
                                               service_rc, service_rs);
-                               rv = 8;
+                               return REC_OPERAND_INV;
                        }
                        src_p = (unsigned char *)cprb_p + sizeof(struct CPRB);
                        src_p += 4;
@@ -2124,11 +2169,22 @@ convert_response(unsigned char *response, unsigned char *buffer,
                        if (service_rc != 0) {
                                service_rs = (int) cprbx_p->ccp_rscode;
                                if ((service_rc == 8) && (service_rs == 66))
-                                       PDEBUG("8/66 on PCIXCC\n");
+                                       PDEBUG("Bad block format on PCXICC\n");
+                               else if ((service_rc == 8) && (service_rs == 770)) {
+                                       PDEBUG("Invalid key length on PCIXCC\n");
+                                       unset_ext_bitlens();
+                                       return REC_USE_PCICA;
+                               }
+                               else if ((service_rc == 8) && (service_rs == 783)) {
+                                       PDEBUG("Extended bitlengths not enabled"
+                                              "on PCIXCC\n");
+                                       unset_ext_bitlens();
+                                       return REC_USE_PCICA;
+                               }
                                else
                                        PRINTK("service rc/rs: %d/%d\n",
                                               service_rc, service_rs);
-                               rv = 8;
+                               return REC_OPERAND_INV;
                        }
                        src_p = (unsigned char *)
                                cprbx_p + sizeof(struct CPRBX);
@@ -2139,12 +2195,10 @@ convert_response(unsigned char *response, unsigned char *buffer,
                }
                break;
        default:
-               break;
+               return REC_BAD_MESSAGE;
        }
 
-       if (rv == 8)
-               return 8;
-       if (rv == 4)
+       if (reply_code)
                switch (reply_code) {
                case REPLY_ERROR_OPERAND_INVALID:
                        return REC_OPERAND_INV;
@@ -2154,8 +2208,14 @@ convert_response(unsigned char *response, unsigned char *buffer,
                        return REC_EVEN_MOD;
                case REPLY_ERROR_MESSAGE_TYPE:
                        return WRONG_DEVICE_TYPE;
+               case REPLY_ERROR_TRANSPORT_FAIL:
+                       PRINTKW("Transport failed (APFS = %02X%02X%02X%02X)\n",
+                               t86m_p->apfs[0], t86m_p->apfs[1],
+                               t86m_p->apfs[2], t86m_p->apfs[3]);
+                       return REC_HARDWAR_ERR;
                default:
-                       return 12;
+                       PRINTKW("reply code = %d\n", reply_code);
+                       return REC_HARDWAR_ERR;
                }
 
        if (service_rc != 0)
@@ -2171,14 +2231,13 @@ convert_response(unsigned char *response, unsigned char *buffer,
        memcpy(tgt_p, src_p, src_l);
        if ((t82h_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
                memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
-               rv = pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l);
-               if (rv != 0)
-                       return rv;
+               if (pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l))
+                       return REC_INVALID_PAD;
        }
        *respbufflen_p = icaMsg_p->outputdatalength;
        if (*respbufflen_p == 0)
                PRINTK("Zero *respbufflen_p\n");
 
-       return rv;
+       return 0;
 }
 
index 8ac1e9b..ab92dea 100644 (file)
@@ -1,11 +1,11 @@
 /*
- *  linux/drivers/s390/misc/z90main.c
+ *  linux/drivers/s390/crypto/z90main.c
  *
- *  z90crypt 1.3.1
+ *  z90crypt 1.3.2
  *
  *  Copyright (C)  2001, 2004 IBM Corporation
  *  Author(s): Robert Burroughs (burrough@us.ibm.com)
- *            Eric Rossman (edrossma@us.ibm.com)
+ *             Eric Rossman (edrossma@us.ibm.com)
  *
  *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  *
@@ -16,7 +16,7 @@
  *
  * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
@@ -33,6 +33,7 @@
 #include <linux/ioctl32.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/kobject_uevent.h>
 #include <linux/proc_fs.h>
 #include <linux/syscalls.h>
 #include <linux/version.h>
 #  error "This kernel is too recent: not supported by this file"
 #endif
 
-#define VERSION_Z90MAIN_C "$Revision: 1.31 $"
+#define VERSION_Z90MAIN_C "$Revision: 1.57 $"
 
-static char z90cmain_version[] __initdata =
+static char z90main_version[] __initdata =
        "z90main.o (" VERSION_Z90MAIN_C "/"
                       VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")";
 
-extern char z90chardware_version[];
+extern char z90hardware_version[];
 
 /**
  * Defaults that may be modified.
@@ -96,7 +97,7 @@ extern char z90chardware_version[];
  * older than CLEANUPTIME seconds in the past.
  */
 #ifndef CLEANUPTIME
-#define CLEANUPTIME 15
+#define CLEANUPTIME 20
 #endif
 
 /**
@@ -116,9 +117,15 @@ extern char z90chardware_version[];
 
 /**
  * Reader should run every READERTIME milliseconds
+ * With the 100Hz patch for s390, z90crypt can lock the system solid while
+ * under heavy load. We'll try to avoid that.
  */
 #ifndef READERTIME
+#if HZ > 1000
 #define READERTIME 2
+#else
+#define READERTIME 10
+#endif
 #endif
 
 /**
@@ -209,18 +216,13 @@ extern char z90chardware_version[];
 #ifndef Z90CRYPT_NUM_DEVS
 #define Z90CRYPT_NUM_DEVS Z90CRYPT_NUM_APS
 #endif
-#ifndef Z90CRYPT_NUM_TYPES
-#define Z90CRYPT_NUM_TYPES 3
-#endif
 
 /**
  * Buffer size for receiving responses. The maximum Response Size
  * is actually the maximum request size, since in an error condition
  * the request itself may be returned unchanged.
  */
-#ifndef MAX_RESPONSE_SIZE
 #define MAX_RESPONSE_SIZE 0x0000077C
-#endif
 
 /**
  * A count and status-byte mask
@@ -246,7 +248,8 @@ struct device_x {
  * All devices are arranged in a single array: 64 APs
  */
 struct device {
-       int              dev_type;          // PCICA, PCICC, or PCIXCC
+       int              dev_type;          // PCICA, PCICC, PCIXCC_MCL2,
+                                           // PCIXCC_MCL3, CEX2C
        enum devstat     dev_stat;          // current device status
        int              dev_self_x;        // Index in array
        int              disabled;          // Set when device is in error
@@ -328,6 +331,7 @@ static int destroy_crypto_device(int);
 static void destroy_z90crypt(void);
 static int refresh_index_array(struct status *, struct device_x *);
 static int probe_device_type(struct device *);
+static int probe_PCIXCC_type(struct device *);
 
 /**
  * proc fs definitions
@@ -449,9 +453,9 @@ static struct miscdevice z90crypt_misc_device = {
 /**
  * Documentation values.
  */
-MODULE_AUTHOR("zLinux Crypto Team: Robert H. Burroughs, Eric D. Rossman"
+MODULE_AUTHOR("zSeries Linux Crypto Team: Robert H. Burroughs, Eric D. Rossman"
              "and Jochen Roehrig");
-MODULE_DESCRIPTION("zLinux Cryptographic Coprocessor device driver, "
+MODULE_DESCRIPTION("zSeries Linux Cryptographic Coprocessor device driver, "
                   "Copyright 2001, 2004 IBM Corporation");
 MODULE_LICENSE("GPL");
 module_param(domain, int, 0);
@@ -554,7 +558,8 @@ trans_modexpo_crt32(unsigned int fd, unsigned int cmd, unsigned long arg,
 
 static int compatible_ioctls[] = {
        ICAZ90STATUS, Z90QUIESCE, Z90STAT_TOTALCOUNT, Z90STAT_PCICACOUNT,
-       Z90STAT_PCICCCOUNT, Z90STAT_PCIXCCCOUNT, Z90STAT_REQUESTQ_COUNT,
+       Z90STAT_PCICCCOUNT, Z90STAT_PCIXCCCOUNT, Z90STAT_PCIXCCMCL2COUNT,
+       Z90STAT_PCIXCCMCL3COUNT, Z90STAT_CEX2CCOUNT, Z90STAT_REQUESTQ_COUNT,
        Z90STAT_PENDINGQ_COUNT, Z90STAT_TOTALOPEN_COUNT, Z90STAT_DOMAIN_INDEX,
        Z90STAT_STATUS_MASK, Z90STAT_QDEPTH_MASK, Z90STAT_PERDEV_REQCNT,
 };
@@ -575,20 +580,33 @@ static int z90_register_ioctl32s(void)
        int result, i;
 
        result = register_ioctl32_conversion(ICARSAMODEXPO, trans_modexpo32);
+       if (result == -EBUSY) {
+               unregister_ioctl32_conversion(ICARSAMODEXPO);
+               result = register_ioctl32_conversion(ICARSAMODEXPO,
+                                                    trans_modexpo32);
+       }
        if (result)
                return result;
        result = register_ioctl32_conversion(ICARSACRT, trans_modexpo_crt32);
+       if (result == -EBUSY) {
+               unregister_ioctl32_conversion(ICARSACRT);
+               result = register_ioctl32_conversion(ICARSACRT,
+                                                    trans_modexpo_crt32);
+       }
        if (result)
                return result;
 
        for(i = 0; i < ARRAY_SIZE(compatible_ioctls); i++) {
-               result = register_ioctl32_conversion(compatible_ioctls[i],NULL);
-               if (result) {
-                       z90_unregister_ioctl32s();
-                       return result;
+               result = register_ioctl32_conversion(compatible_ioctls[i], 0);
+               if (result == -EBUSY) {
+                       unregister_ioctl32_conversion(compatible_ioctls[i]);
+                       result = register_ioctl32_conversion(
+                                                      compatible_ioctls[i], 0);
                }
+               if (result)
+                       return result;
        }
-       return result;
+       return 0;
 }
 #else // !CONFIG_COMPAT
 static inline void z90_unregister_ioctl32s(void)
@@ -612,10 +630,15 @@ z90crypt_init_module(void)
 
        PDEBUG("PID %d\n", PID());
 
+       if ((domain < -1) || (domain > 15)) {
+               PRINTKW("Invalid param: domain = %d.  Not loading.\n", domain);
+               return -EINVAL;
+       }
+
 #ifndef Z90CRYPT_USE_HOTPLUG
        /* Register as misc device with given minor (or get a dynamic one). */
        result = misc_register(&z90crypt_misc_device);
-       if (result <0) {
+       if (result < 0) {
                PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n",
                        z90crypt_misc_device.minor, result);
                return result;
@@ -647,8 +670,8 @@ z90crypt_init_module(void)
                PRINTKN("Version %d.%d.%d loaded, built on %s %s\n",
                        z90crypt_VERSION, z90crypt_RELEASE, z90crypt_VARIANT,
                        __DATE__, __TIME__);
-               PRINTKN("%s\n", z90cmain_version);
-               PRINTKN("%s\n", z90chardware_version);
+               PRINTKN("%s\n", z90main_version);
+               PRINTKN("%s\n", z90hardware_version);
                PDEBUG("create_z90crypt (domain index %d) successful.\n",
                       domain);
        } else
@@ -923,7 +946,26 @@ get_status_PCICCcount(void)
 static inline int
 get_status_PCIXCCcount(void)
 {
-       return z90crypt.hdware_info->type_mask[PCIXCC].st_count;
+       return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count +
+              z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
+}
+
+static inline int
+get_status_PCIXCCMCL2count(void)
+{
+       return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count;
+}
+
+static inline int
+get_status_PCIXCCMCL3count(void)
+{
+       return z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
+}
+
+static inline int
+get_status_CEX2Ccount(void)
+{
+       return z90crypt.hdware_info->type_mask[CEX2C].st_count;
 }
 
 static inline int
@@ -1016,8 +1058,8 @@ init_work_element(struct work_element *we_p,
        we_p->audit[2] = 0x00;
        we_p->resp_buff_size = 0;
        we_p->retcode = 0;
-       we_p->devindex = -1; // send_to_crypto selects the device
-       we_p->devtype = -1;  // getCryptoBuffer selects the type
+       we_p->devindex = -1;
+       we_p->devtype = -1;
        atomic_set(&we_p->alarmrung, 0);
        init_waitqueue_head(&we_p->waitq);
        INIT_LIST_HEAD(&(we_p->liste));
@@ -1040,42 +1082,113 @@ allocate_work_element(struct work_element **we_pp,
 static inline void
 remove_device(struct device *device_p)
 {
-       if (!device_p || device_p->disabled != 0)
+       if (!device_p || (device_p->disabled != 0))
                return;
        device_p->disabled = 1;
        z90crypt.hdware_info->type_mask[device_p->dev_type].disabled_count++;
        z90crypt.hdware_info->hdware_mask.disabled_count++;
 }
 
+/**
+ * Bitlength limits for each card
+ *
+ * There are new MCLs which allow more bitlengths. See the table for details.
+ * The MCL must be applied and the newer bitlengths enabled for these to work.
+ *
+ * Card Type    Old limit    New limit
+ * PCICC         512-1024     512-2048
+ * PCIXCC_MCL2   512-2048     no change (applying this MCL == card is MCL3+)
+ * PCIXCC_MCL3   512-2048     128-2048
+ * CEX2C         512-2048     128-2048
+ *
+ * ext_bitlens (extended bitlengths) is a global, since you should not apply an
+ * MCL to just one card in a machine. We assume, at first, that all cards have
+ * these capabilities.
+ */
+int ext_bitlens = 1; // This is global
+#define PCIXCC_MIN_MOD_SIZE     16     //  128 bits
+#define OLD_PCIXCC_MIN_MOD_SIZE         64     //  512 bits
+#define PCICC_MIN_MOD_SIZE      64     //  512 bits
+#define OLD_PCICC_MAX_MOD_SIZE 128     // 1024 bits
+#define MAX_MOD_SIZE           256     // 2048 bits
+
 static inline int
-select_device_type(int *dev_type_p)
+select_device_type(int *dev_type_p, int bytelength)
 {
+       static int count = 0;
+       int PCICA_avail, PCIXCC_MCL3_avail, CEX2C_avail, index_to_use;
        struct status *stat;
        if ((*dev_type_p != PCICC) && (*dev_type_p != PCICA) &&
-           (*dev_type_p != PCIXCC) && (*dev_type_p != ANYDEV))
+           (*dev_type_p != PCIXCC_MCL2) && (*dev_type_p != PCIXCC_MCL3) &&
+           (*dev_type_p != CEX2C) && (*dev_type_p != ANYDEV))
                return -1;
        if (*dev_type_p != ANYDEV) {
                stat = &z90crypt.hdware_info->type_mask[*dev_type_p];
                if (stat->st_count >
-                   stat->disabled_count + stat->user_disabled_count)
+                   (stat->disabled_count + stat->user_disabled_count))
                        return 0;
                return -1;
        }
 
+       /* Assumption: PCICA, PCIXCC_MCL3, and CEX2C are all similar in speed */
        stat = &z90crypt.hdware_info->type_mask[PCICA];
-       if (stat->st_count > stat->disabled_count + stat->user_disabled_count) {
-               *dev_type_p = PCICA;
+       PCICA_avail = stat->st_count -
+                       (stat->disabled_count + stat->user_disabled_count);
+       stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL3];
+       PCIXCC_MCL3_avail = stat->st_count -
+                       (stat->disabled_count + stat->user_disabled_count);
+       stat = &z90crypt.hdware_info->type_mask[CEX2C];
+       CEX2C_avail = stat->st_count -
+                       (stat->disabled_count + stat->user_disabled_count);
+       if (PCICA_avail || PCIXCC_MCL3_avail || CEX2C_avail) {
+               /**
+                * bitlength is a factor, PCICA is the most capable, even with
+                * the new MCL.
+                */
+               if ((bytelength < PCIXCC_MIN_MOD_SIZE) ||
+                   (!ext_bitlens && (bytelength < OLD_PCIXCC_MIN_MOD_SIZE))) {
+                       if (!PCICA_avail)
+                               return -1;
+                       else {
+                               *dev_type_p = PCICA;
+                               return 0;
+                       }
+               }
+
+               index_to_use = count % (PCICA_avail + PCIXCC_MCL3_avail +
+                                       CEX2C_avail);
+               if (index_to_use < PCICA_avail)
+                       *dev_type_p = PCICA;
+               else if (index_to_use < (PCICA_avail + PCIXCC_MCL3_avail))
+                       *dev_type_p = PCIXCC_MCL3;
+               else
+                       *dev_type_p = CEX2C;
+               count++;
                return 0;
        }
 
-       stat = &z90crypt.hdware_info->type_mask[PCIXCC];
-       if (stat->st_count > stat->disabled_count + stat->user_disabled_count) {
-               *dev_type_p = PCIXCC;
+       /* Less than OLD_PCIXCC_MIN_MOD_SIZE cannot go to a PCIXCC_MCL2 */
+       if (bytelength < OLD_PCIXCC_MIN_MOD_SIZE)
+               return -1;
+       stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL2];
+       if (stat->st_count >
+           (stat->disabled_count + stat->user_disabled_count)) {
+               *dev_type_p = PCIXCC_MCL2;
                return 0;
        }
 
+       /**
+        * Less than PCICC_MIN_MOD_SIZE or more than OLD_PCICC_MAX_MOD_SIZE
+        * (if we don't have the MCL applied and the newer bitlengths enabled)
+        * cannot go to a PCICC
+        */
+       if ((bytelength < PCICC_MIN_MOD_SIZE) ||
+           (!ext_bitlens && (bytelength > OLD_PCICC_MAX_MOD_SIZE))) {
+               return -1;
+       }
        stat = &z90crypt.hdware_info->type_mask[PCICC];
-       if (stat->st_count > stat->disabled_count + stat->user_disabled_count) {
+       if (stat->st_count >
+           (stat->disabled_count + stat->user_disabled_count)) {
                *dev_type_p = PCICC;
                return 0;
        }
@@ -1087,7 +1200,7 @@ select_device_type(int *dev_type_p)
  * Try the selected number, then the selected type (can be ANYDEV)
  */
 static inline int
-select_device(int *dev_type_p, int *device_nr_p)
+select_device(int *dev_type_p, int *device_nr_p, int bytelength)
 {
        int i, indx, devTp, low_count, low_indx;
        struct device_x *index_p;
@@ -1099,9 +1212,9 @@ select_device(int *dev_type_p, int *device_nr_p)
                dev_ptr = z90crypt.device_p[*device_nr_p];
 
                if (dev_ptr &&
-                   dev_ptr->dev_stat != DEV_GONE &&
-                   dev_ptr->disabled == 0 &&
-                   dev_ptr->user_disabled == 0) {
+                   (dev_ptr->dev_stat != DEV_GONE) &&
+                   (dev_ptr->disabled == 0) &&
+                   (dev_ptr->user_disabled == 0)) {
                        PDEBUG("selected by number, index = %d\n",
                               *device_nr_p);
                        *dev_type_p = dev_ptr->dev_type;
@@ -1111,7 +1224,7 @@ select_device(int *dev_type_p, int *device_nr_p)
        *device_nr_p = -1;
        PDEBUG("trying type = %d\n", *dev_type_p);
        devTp = *dev_type_p;
-       if (select_device_type(&devTp) == -1) {
+       if (select_device_type(&devTp, bytelength) == -1) {
                PDEBUG("failed to select by type\n");
                return -1;
        }
@@ -1123,11 +1236,11 @@ select_device(int *dev_type_p, int *device_nr_p)
                indx = index_p->device_index[i];
                dev_ptr = z90crypt.device_p[indx];
                if (dev_ptr &&
-                   dev_ptr->dev_stat != DEV_GONE &&
-                   dev_ptr->disabled == 0 &&
-                   dev_ptr->user_disabled == 0 &&
-                   devTp == dev_ptr->dev_type &&
-                   low_count > dev_ptr->dev_caller_count) {
+                   (dev_ptr->dev_stat != DEV_GONE) &&
+                   (dev_ptr->disabled == 0) &&
+                   (dev_ptr->user_disabled == 0) &&
+                   (devTp == dev_ptr->dev_type) &&
+                   (low_count > dev_ptr->dev_caller_count)) {
                        low_count = dev_ptr->dev_caller_count;
                        low_indx = indx;
                }
@@ -1142,12 +1255,13 @@ send_to_crypto_device(struct work_element *we_p)
        struct caller *caller_p;
        struct device *device_p;
        int dev_nr;
+       int bytelen = ((struct ica_rsa_modexpo *)we_p->buffer)->inputdatalength;
 
        if (!we_p->requestptr)
                return SEN_FATAL_ERROR;
        caller_p = (struct caller *)we_p->requestptr;
        dev_nr = we_p->devindex;
-       if (select_device(&we_p->devtype, &dev_nr) == -1) {
+       if (select_device(&we_p->devtype, &dev_nr, bytelen) == -1) {
                if (z90crypt.hdware_info->hdware_mask.st_count != 0)
                        return SEN_RETRY;
                else
@@ -1296,15 +1410,6 @@ z90crypt_process_results(struct work_element *we_p, char __user *buf)
 static unsigned char NULL_psmid[8] =
 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
-/**
- * MIN_MOD_SIZE is a PCICC and PCIXCC limit.
- * MAX_PCICC_MOD_SIZE is a hard limit for the PCICC.
- * MAX_MOD_SIZE is a hard limit for the PCIXCC and PCICA.
- */
-#define MIN_MOD_SIZE 64
-#define MAX_PCICC_MOD_SIZE 128
-#define MAX_MOD_SIZE 256
-
 /**
  * Used in device configuration functions
  */
@@ -1361,7 +1466,8 @@ build_caller(struct work_element *we_p, short function)
        struct caller *caller_p = (struct caller *)we_p->requestptr;
 
        if ((we_p->devtype != PCICC) && (we_p->devtype != PCICA) &&
-           (we_p->devtype != PCIXCC))
+           (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
+           (we_p->devtype != CEX2C))
                return SEN_NOT_AVAIL;
 
        memcpy(caller_p->caller_id, we_p->caller_id,
@@ -1393,9 +1499,8 @@ unbuild_caller(struct device *device_p, struct caller *caller_p)
                return;
        if (caller_p->caller_liste.next && caller_p->caller_liste.prev)
                if (!list_empty(&caller_p->caller_liste)) {
-                       list_del(&caller_p->caller_liste);
+                       list_del_init(&caller_p->caller_liste);
                        device_p->dev_caller_count--;
-                       INIT_LIST_HEAD(&caller_p->caller_liste);
                }
        memset(caller_p->caller_id, 0, sizeof(caller_p->caller_id));
 }
@@ -1430,7 +1535,8 @@ get_crypto_request_buffer(struct work_element *we_p)
        }
 
        if ((we_p->devtype != PCICA) && (we_p->devtype != PCICC) &&
-           (we_p->devtype != PCIXCC) && (we_p->devtype != ANYDEV)) {
+           (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
+           (we_p->devtype != CEX2C) && (we_p->devtype != ANYDEV)) {
                PRINTK("invalid device type\n");
                return SEN_USER_ERROR;
        }
@@ -1494,7 +1600,7 @@ get_crypto_request_buffer(struct work_element *we_p)
        if (rv != 0)
                return rv;
 
-       if (select_device_type(&we_p->devtype) < 0)
+       if (select_device_type(&we_p->devtype, mex_p->inputdatalength) < 0)
                return SEN_NOT_AVAIL;
 
        temp_buffer = (unsigned char *)we_p + sizeof(struct work_element) +
@@ -1510,13 +1616,19 @@ get_crypto_request_buffer(struct work_element *we_p)
                function = PCI_FUNC_KEY_ENCRYPT;
                break;
        /**
-        * PCIXCC does all Mod-Expo form with a simple RSA mod-expo
+        * PCIXCC_MCL2 does all Mod-Expo form with a simple RSA mod-expo
         * operation, and all CRT forms with a PKCS-1.2 format decrypt.
+        * PCIXCC_MCL3 and CEX2C do all Mod-Expo and CRT forms with a simple RSA
+        * mod-expo operation
         */
-       case PCIXCC:
-               /* Anything less than MIN_MOD_SIZE MUST go to a PCICA */
-               if (mex_p->inputdatalength < MIN_MOD_SIZE)
-                       return SEN_NOT_AVAIL;
+       case PCIXCC_MCL2:
+               if (we_p->funccode == ICARSAMODEXPO)
+                       function = PCI_FUNC_KEY_ENCRYPT;
+               else
+                       function = PCI_FUNC_KEY_DECRYPT;
+               break;
+       case PCIXCC_MCL3:
+       case CEX2C:
                if (we_p->funccode == ICARSAMODEXPO)
                        function = PCI_FUNC_KEY_ENCRYPT;
                else
@@ -1526,14 +1638,6 @@ get_crypto_request_buffer(struct work_element *we_p)
         * PCICC does everything as a PKCS-1.2 format request
         */
        case PCICC:
-               /* Anything less than MIN_MOD_SIZE MUST go to a PCICA */
-               if (mex_p->inputdatalength < MIN_MOD_SIZE) {
-                       return SEN_NOT_AVAIL;
-               }
-               /* Anythings over MAX_PCICC_MOD_SIZE MUST go to a PCICA */
-               if (mex_p->inputdatalength > MAX_PCICC_MOD_SIZE) {
-                       return SEN_NOT_AVAIL;
-               }
                /* PCICC cannot handle input that is is PKCS#1.1 padded */
                if (is_PKCS11_padded(temp_buffer, mex_p->inputdatalength)) {
                        return SEN_NOT_AVAIL;
@@ -1593,6 +1697,7 @@ z90crypt_prepare(struct work_element *we_p, unsigned int funccode,
                rv = -ENODEV;
                break;
        case SEN_NOT_AVAIL:
+       case EGETBUFF:
                rv = -EGETBUFF;
                break;
        default:
@@ -1613,14 +1718,14 @@ purge_work_element(struct work_element *we_p)
        spin_lock_irq(&queuespinlock);
        list_for_each(lptr, &request_list) {
                if (lptr == &we_p->liste) {
-                       list_del(lptr);
+                       list_del_init(lptr);
                        requestq_count--;
                        break;
                }
        }
        list_for_each(lptr, &pending_list) {
                if (lptr == &we_p->liste) {
-                       list_del(lptr);
+                       list_del_init(lptr);
                        pendingq_count--;
                        break;
                }
@@ -1659,14 +1764,13 @@ z90crypt_rsa(struct priv_data *private_data_p, pid_t pid,
        if ((we_p->status[0] & STAT_FAILED)) {
                switch (rv) {
                /**
-                * EINVAL *after* receive is almost always padding
-                * error issued by a PCICC or PCIXCC. We convert this
-                * return value to -EGETBUFF which should trigger a
-                * fallback to software.
+                * EINVAL *after* receive is almost always a padding error or
+                * length error issued by a coprocessor (not an accelerator).
+                * We convert this return value to -EGETBUFF which should
+                * trigger a fallback to software.
                 */
                case -EINVAL:
-                       if ((we_p->devtype == PCICC) ||
-                           (we_p->devtype == PCIXCC))
+                       if (we_p->devtype != PCICA)
                                rv = -EGETBUFF;
                        break;
                case -ETIMEOUT:
@@ -1710,7 +1814,8 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
        unsigned int *reqcnt;
        struct ica_z90_status *pstat;
        int ret, i, loopLim, tempstat;
-       static int deprecated_msg_count = 0;
+       static int deprecated_msg_count1 = 0;
+       static int deprecated_msg_count2 = 0;
 
        PDEBUG("filp %p (PID %d), cmd 0x%08X\n", filp, PID(), cmd);
        PDEBUG("cmd 0x%08X: dir %s, size 0x%04X, type 0x%02X, nr 0x%02X\n",
@@ -1765,8 +1870,20 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
                        ret = -EFAULT;
                break;
 
-       case Z90STAT_PCIXCCCOUNT:
-               tempstat = get_status_PCIXCCcount();
+       case Z90STAT_PCIXCCMCL2COUNT:
+               tempstat = get_status_PCIXCCMCL2count();
+               if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+                       ret = -EFAULT;
+               break;
+
+       case Z90STAT_PCIXCCMCL3COUNT:
+               tempstat = get_status_PCIXCCMCL3count();
+               if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+                       ret = -EFAULT;
+               break;
+
+       case Z90STAT_CEX2CCOUNT:
+               tempstat = get_status_CEX2Ccount();
                if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
                        ret = -EFAULT;
                break;
@@ -1838,10 +1955,10 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
 
                /* THIS IS DEPRECATED.  USE THE NEW STATUS CALLS */
        case ICAZ90STATUS:
-               if (deprecated_msg_count < 100) {
+               if (deprecated_msg_count1 < 20) {
                        PRINTK("deprecated call to ioctl (ICAZ90STATUS)!\n");
-                       deprecated_msg_count++;
-                       if (deprecated_msg_count == 100)
+                       deprecated_msg_count1++;
+                       if (deprecated_msg_count1 == 20)
                                PRINTK("No longer issuing messages related to "
                                       "deprecated call to ICAZ90STATUS.\n");
                }
@@ -1869,6 +1986,21 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
                kfree(pstat);
                break;
 
+               /* THIS IS DEPRECATED.  USE THE NEW STATUS CALLS */
+       case Z90STAT_PCIXCCCOUNT:
+               if (deprecated_msg_count2 < 20) {
+                       PRINTK("deprecated ioctl (Z90STAT_PCIXCCCOUNT)!\n");
+                       deprecated_msg_count2++;
+                       if (deprecated_msg_count2 == 20)
+                               PRINTK("No longer issuing messages about depre"
+                                      "cated ioctl Z90STAT_PCIXCCCOUNT.\n");
+               }
+
+               tempstat = get_status_PCIXCCcount();
+               if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
+                       ret = -EFAULT;
+               break;
+
        case Z90QUIESCE:
                if (current->euid != 0) {
                        PRINTK("QUIESCE fails: euid %d\n",
@@ -1990,8 +2122,12 @@ z90crypt_status(char *resp_buff, char **start, off_t offset,
                get_status_PCICAcount());
        len += sprintf(resp_buff+len, "PCICC count: %d\n",
                get_status_PCICCcount());
-       len += sprintf(resp_buff+len, "PCIXCC count: %d\n",
-               get_status_PCIXCCcount());
+       len += sprintf(resp_buff+len, "PCIXCC MCL2 count: %d\n",
+               get_status_PCIXCCMCL2count());
+       len += sprintf(resp_buff+len, "PCIXCC MCL3 count: %d\n",
+               get_status_PCIXCCMCL3count());
+       len += sprintf(resp_buff+len, "CEX2C count: %d\n",
+               get_status_CEX2Ccount());
        len += sprintf(resp_buff+len, "requestq count: %d\n",
                get_status_requestq_count());
        len += sprintf(resp_buff+len, "pendingq count: %d\n",
@@ -1999,7 +2135,8 @@ z90crypt_status(char *resp_buff, char **start, off_t offset,
        len += sprintf(resp_buff+len, "Total open handles: %d\n\n",
                get_status_totalopen_count());
        len += sprinthx(
-               "Online devices: 1 means PCICA, 2 means PCICC, 3 means PCIXCC",
+               "Online devices: 1: PCICA, 2: PCICC, 3: PCIXCC (MCL2), "
+               "4: PCIXCC (MCL3), 5: CEX2C",
                resp_buff+len,
                get_status_status_mask(workarea),
                Z90CRYPT_NUM_APS);
@@ -2171,6 +2308,8 @@ z90crypt_status_write(struct file *file, const char __user *buffer,
                case '1':
                case '2':
                case '3':
+               case '4':
+               case '5':
                        j++;
                        break;
                case 'd':
@@ -2228,13 +2367,12 @@ receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
        dev_ptr = z90crypt.device_p[index];
        rv = 0;
        do {
-               PDEBUG("Dequeue called for device %d\n", index);
                if (!dev_ptr || dev_ptr->disabled) {
-                       rv = REC_NO_RESPONSE;
+                       rv = REC_NO_WORK; // a disabled device can't return work
                        break;
                }
                if (dev_ptr->dev_self_x != index) {
-                       PRINTK("Corrupt dev ptr in receive_from_AP\n");
+                       PRINTKC("Corrupt dev ptr\n");
                        z90crypt.terminating = 1;
                        rv = REC_FATAL_ERROR;
                        break;
@@ -2244,6 +2382,7 @@ receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
                        PRINTK("dev_resp_l = %d, dev_resp_p = %p\n",
                               dev_ptr->dev_resp_l, dev_ptr->dev_resp_p);
                } else {
+                       PDEBUG("Dequeue called for device %d\n", index);
                        dv = receive_from_AP(index, z90crypt.cdx,
                                             dev_ptr->dev_resp_l,
                                             dev_ptr->dev_resp_p, psmid);
@@ -2283,15 +2422,18 @@ receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
                        if (!memcmp(caller_p->caller_id, psmid,
                                    sizeof(caller_p->caller_id))) {
                                if (!list_empty(&caller_p->caller_liste)) {
-                                       list_del(ptr);
+                                       list_del_init(ptr);
                                        dev_ptr->dev_caller_count--;
-                                       INIT_LIST_HEAD(&caller_p->caller_liste);
                                        break;
                                }
                        }
                        caller_p = 0;
                }
                if (!caller_p) {
+                       PRINTKW("Unable to locate PSMID %02X%02X%02X%02X%02X"
+                               "%02X%02X%02X in device list\n",
+                               psmid[0], psmid[1], psmid[2], psmid[3],
+                               psmid[4], psmid[5], psmid[6], psmid[7]);
                        rv = REC_USER_GONE;
                        break;
                }
@@ -2300,22 +2442,22 @@ receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
                rv = convert_response(dev_ptr->dev_resp_p,
                                      caller_p->caller_buf_p, buff_len_p, buff);
                switch (rv) {
+               case REC_USE_PCICA:
+                       break;
                case REC_OPERAND_INV:
-                       PDEBUG("dev %d: user error %d\n", index, rv);
+               case REC_OPERAND_SIZE:
+               case REC_EVEN_MOD:
+               case REC_INVALID_PAD:
+                       PDEBUG("device %d: 'user error' %d\n", index, rv);
                        break;
                case WRONG_DEVICE_TYPE:
                case REC_HARDWAR_ERR:
                case REC_BAD_MESSAGE:
-                       PRINTK("dev %d: hardware error %d\n",
-                              index, rv);
+                       PRINTKW("device %d: hardware error %d\n", index, rv);
                        rv = REC_NO_RESPONSE;
                        break;
-               case REC_RELEASED:
-                       PDEBUG("dev %d: REC_RELEASED = %d\n",
-                              index, rv);
-                       break;
                default:
-                       PDEBUG("dev %d: rv = %d\n", index, rv);
+                       PDEBUG("device %d: rv = %d\n", index, rv);
                        break;
                }
        } while (0);
@@ -2329,6 +2471,7 @@ receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
                        PRINTK("Zero *buff_len_p\n");
                break;
        case REC_NO_RESPONSE:
+               PRINTKW("Removing device %d from availability\n", index);
                remove_device(dev_ptr);
                break;
        }
@@ -2349,7 +2492,7 @@ helper_send_work(int index)
                return;
        requestq_count--;
        rq_p = list_entry(request_list.next, struct work_element, liste);
-       list_del(&rq_p->liste);
+       list_del_init(&rq_p->liste);
        rq_p->audit[1] |= FP_REMREQUEST;
        if (rq_p->devtype == SHRT2DEVPTR(index)->dev_type) {
                rq_p->devindex = SHRT2LONG(index);
@@ -2408,7 +2551,7 @@ helper_handle_work_element(int index, unsigned char psmid[8], int rc,
        list_for_each_safe(lptr, tptr, &pending_list) {
                pq_p = list_entry(lptr, struct work_element, liste);
                if (!memcmp(pq_p->caller_id, psmid, sizeof(pq_p->caller_id))) {
-                       list_del(lptr);
+                       list_del_init(lptr);
                        pendingq_count--;
                        pq_p->audit[1] |= FP_NOTPENDING;
                        break;
@@ -2441,6 +2584,10 @@ helper_handle_work_element(int index, unsigned char psmid[8], int rc,
                        pq_p->retcode = -EINVAL;
                        pq_p->status[0] |= STAT_FAILED;
                        break;
+               case REC_USE_PCICA:
+                       pq_p->retcode = -ERESTARTSYS;
+                       pq_p->status[0] |= STAT_FAILED;
+                       break;
                case REC_NO_RESPONSE:
                default:
                        if (z90crypt.mask.st_count > 1)
@@ -2461,7 +2608,7 @@ helper_handle_work_element(int index, unsigned char psmid[8], int rc,
  * return TRUE if the work element should be removed from the queue
  */
 static inline int
-helper_receive_rc(int index, int *rc_p, int *workavail_p)
+helper_receive_rc(int index, int *rc_p)
 {
        switch (*rc_p) {
        case 0:
@@ -2469,26 +2616,26 @@ helper_receive_rc(int index, int *rc_p, int *workavail_p)
        case REC_OPERAND_SIZE:
        case REC_EVEN_MOD:
        case REC_INVALID_PAD:
-               return 1;
+       case REC_USE_PCICA:
+               break;
 
        case REC_BUSY:
        case REC_NO_WORK:
        case REC_EMPTY:
        case REC_RETRY_DEV:
        case REC_FATAL_ERROR:
-               break;
+               return 0;
 
        case REC_NO_RESPONSE:
-               *workavail_p = 0;
                break;
 
        default:
-               PRINTK("rc %d, device %d\n", *rc_p, SHRT2LONG(index));
+               PRINTK("rc %d, device %d converted to REC_NO_RESPONSE\n",
+                      *rc_p, SHRT2LONG(index));
                *rc_p = REC_NO_RESPONSE;
-               *workavail_p = 0;
                break;
        }
-       return 0;
+       return 1;
 }
 
 static inline void
@@ -2503,21 +2650,18 @@ z90crypt_schedule_reader_timer(void)
 static void
 z90crypt_reader_task(unsigned long ptr)
 {
-       int workavail, remaining, index, rc, buff_len;
+       int workavail, index, rc, buff_len;
        unsigned char   psmid[8];
        unsigned char __user *resp_addr;
        static unsigned char buff[1024];
 
-       PDEBUG("jiffies %ld\n", jiffies);
-
        /**
         * we use workavail = 2 to ensure 2 passes with nothing dequeued before
-        * exiting the loop. If remaining == 0 after the loop, there is no work
-        * remaining on the queues.
+        * exiting the loop. If pendingq_count == 0 after the loop, there is no
+        * work remaining on the queues.
         */
        resp_addr = 0;
        workavail = 2;
-       remaining = 0;
        buff_len = 0;
        while (workavail) {
                workavail--;
@@ -2535,7 +2679,7 @@ z90crypt_reader_task(unsigned long ptr)
                                                        &resp_addr);
                        PDEBUG("Dequeued: rc = %d.\n", rc);
 
-                       if (helper_receive_rc(index, &rc, &workavail)) {
+                       if (helper_receive_rc(index, &rc)) {
                                if (rc != REC_NO_RESPONSE) {
                                        helper_send_work(index);
                                        workavail = 2;
@@ -2547,19 +2691,14 @@ z90crypt_reader_task(unsigned long ptr)
                        }
 
                        if (rc == REC_FATAL_ERROR)
-                               remaining = 0;
-                       else if (rc != REC_NO_RESPONSE)
-                               remaining +=
-                                       SHRT2DEVPTR(index)->dev_caller_count;
+                               PRINTKW("REC_FATAL_ERROR from device %d!\n",
+                                       SHRT2LONG(index));
                }
                spin_unlock_irq(&queuespinlock);
        }
 
-       if (remaining) {
-               spin_lock_irq(&queuespinlock);
+       if (pendingq_count)
                z90crypt_schedule_reader_timer();
-               spin_unlock_irq(&queuespinlock);
-       }
 }
 
 static inline void
@@ -2606,7 +2745,7 @@ helper_drain_queues(void)
                pq_p->status[0] |= STAT_FAILED;
                unbuild_caller(LONG2DEVPTR(pq_p->devindex),
                               (struct caller *)pq_p->requestptr);
-               list_del(lptr);
+               list_del_init(lptr);
                pendingq_count--;
                pq_p->audit[1] |= FP_NOTPENDING;
                pq_p->audit[1] |= FP_AWAKENING;
@@ -2618,7 +2757,7 @@ helper_drain_queues(void)
                pq_p = list_entry(lptr, struct work_element, liste);
                pq_p->retcode = -ENODEV;
                pq_p->status[0] |= STAT_FAILED;
-               list_del(lptr);
+               list_del_init(lptr);
                requestq_count--;
                pq_p->audit[1] |= FP_REMREQUEST;
                pq_p->audit[1] |= FP_AWAKENING;
@@ -2640,12 +2779,21 @@ helper_timeout_requests(void)
                pq_p = list_entry(lptr, struct work_element, liste);
                if (pq_p->requestsent >= timelimit)
                        break;
+               PRINTKW("Purging(PQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
+                      ((struct caller *)pq_p->requestptr)->caller_id[0],
+                      ((struct caller *)pq_p->requestptr)->caller_id[1],
+                      ((struct caller *)pq_p->requestptr)->caller_id[2],
+                      ((struct caller *)pq_p->requestptr)->caller_id[3],
+                      ((struct caller *)pq_p->requestptr)->caller_id[4],
+                      ((struct caller *)pq_p->requestptr)->caller_id[5],
+                      ((struct caller *)pq_p->requestptr)->caller_id[6],
+                      ((struct caller *)pq_p->requestptr)->caller_id[7]);
                pq_p->retcode = -ETIMEOUT;
                pq_p->status[0] |= STAT_FAILED;
                /* get this off any caller queue it may be on */
                unbuild_caller(LONG2DEVPTR(pq_p->devindex),
                               (struct caller *) pq_p->requestptr);
-               list_del(lptr);
+               list_del_init(lptr);
                pendingq_count--;
                pq_p->audit[1] |= FP_TIMEDOUT;
                pq_p->audit[1] |= FP_NOTPENDING;
@@ -2663,9 +2811,18 @@ helper_timeout_requests(void)
                        pq_p = list_entry(lptr, struct work_element, liste);
                        if (pq_p->requestsent >= timelimit)
                                break;
+               PRINTKW("Purging(RQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
+                      ((struct caller *)pq_p->requestptr)->caller_id[0],
+                      ((struct caller *)pq_p->requestptr)->caller_id[1],
+                      ((struct caller *)pq_p->requestptr)->caller_id[2],
+                      ((struct caller *)pq_p->requestptr)->caller_id[3],
+                      ((struct caller *)pq_p->requestptr)->caller_id[4],
+                      ((struct caller *)pq_p->requestptr)->caller_id[5],
+                      ((struct caller *)pq_p->requestptr)->caller_id[6],
+                      ((struct caller *)pq_p->requestptr)->caller_id[7]);
                        pq_p->retcode = -ETIMEOUT;
                        pq_p->status[0] |= STAT_FAILED;
-                       list_del(lptr);
+                       list_del_init(lptr);
                        requestq_count--;
                        pq_p->audit[1] |= FP_TIMEDOUT;
                        pq_p->audit[1] |= FP_REMREQUEST;
@@ -2737,15 +2894,15 @@ helper_scan_devices(int cdx_array[16], int *cdx_p, int *correct_cdx_found)
 {
        enum hdstat hd_stat;
        int q_depth, dev_type;
-       int i, j, k;
+       int indx, chkdom, numdomains;
 
-       q_depth = dev_type = k = 0;
-       for (i = 0; i < z90crypt.max_count; i++) {
+       q_depth = dev_type = numdomains = 0;
+       for (chkdom = 0; chkdom <= 15; cdx_array[chkdom++] = -1);
+       for (indx = 0; indx < z90crypt.max_count; indx++) {
                hd_stat = HD_NOT_THERE;
-               for (j = 0; j <= 15; cdx_array[j++] = -1);
-               k = 0;
-               for (j = 0; j <= 15; j++) {
-                       hd_stat = query_online(i, j, MAX_RESET,
+               numdomains = 0;
+               for (chkdom = 0; chkdom <= 15; chkdom++) {
+                       hd_stat = query_online(indx, chkdom, MAX_RESET,
                                               &q_depth, &dev_type);
                        if (hd_stat == HD_TSQ_EXCEPTION) {
                                z90crypt.terminating = 1;
@@ -2753,29 +2910,30 @@ helper_scan_devices(int cdx_array[16], int *cdx_p, int *correct_cdx_found)
                                break;
                        }
                        if (hd_stat == HD_ONLINE) {
-                               cdx_array[k++] = j;
-                               if (*cdx_p == j) {
+                               cdx_array[numdomains++] = chkdom;
+                               if (*cdx_p == chkdom) {
                                        *correct_cdx_found  = 1;
                                        break;
                                }
                        }
                }
-               if ((*correct_cdx_found == 1) || (k != 0))
+               if ((*correct_cdx_found == 1) || (numdomains != 0))
                        break;
                if (z90crypt.terminating)
                        break;
        }
-       return k;
+       return numdomains;
 }
 
 static inline int
 probe_crypto_domain(int *cdx_p)
 {
        int cdx_array[16];
-       int correct_cdx_found, k;
+       char cdx_array_text[53], temp[5];
+       int correct_cdx_found, numdomains;
 
        correct_cdx_found = 0;
-       k = helper_scan_devices(cdx_array, cdx_p, &correct_cdx_found);
+       numdomains = helper_scan_devices(cdx_array, cdx_p, &correct_cdx_found);
 
        if (z90crypt.terminating)
                return TSQ_FATAL_ERROR;
@@ -2783,23 +2941,31 @@ probe_crypto_domain(int *cdx_p)
        if (correct_cdx_found)
                return 0;
 
-       if (k == 0) {
-               *cdx_p = 0;
-               return 0;
+       if (numdomains == 0) {
+               PRINTKW("Unable to find crypto domain: No devices found\n");
+               return Z90C_NO_DEVICES;
        }
 
-       if (k == 1) {
-               if ((*cdx_p == -1) || !z90crypt.domain_established) {
+       if (numdomains == 1) {
+               if (*cdx_p == -1) {
                        *cdx_p = cdx_array[0];
                        return 0;
                }
-               if (*cdx_p != cdx_array[0]) {
-                       PRINTK("incorrect domain: specified = %d, found = %d\n",
-                              *cdx_p, cdx_array[0]);
-                       return Z90C_INCORRECT_DOMAIN;
-               }
+               PRINTKW("incorrect domain: specified = %d, found = %d\n",
+                      *cdx_p, cdx_array[0]);
+               return Z90C_INCORRECT_DOMAIN;
+       }
+
+       numdomains--;
+       sprintf(cdx_array_text, "%d", cdx_array[numdomains]);
+       while (numdomains) {
+               numdomains--;
+               sprintf(temp, ", %d", cdx_array[numdomains]);
+               strcat(cdx_array_text, temp);
        }
 
+       PRINTKW("ambiguous domain detected: specified = %d, found array = %s\n",
+               *cdx_p, cdx_array_text);
        return Z90C_AMBIGUOUS_DOMAIN;
 }
 
@@ -2807,7 +2973,7 @@ static int
 refresh_z90crypt(int *cdx_p)
 {
        int i, j, indx, rv;
-       struct status local_mask;
+       static struct status local_mask;
        struct device *devPtr;
        unsigned char oldStat, newStat;
        int return_unchanged;
@@ -2818,25 +2984,14 @@ refresh_z90crypt(int *cdx_p)
                return TSQ_FATAL_ERROR;
        rv = 0;
        if (!z90crypt.hdware_info->hdware_mask.st_count &&
-           !z90crypt.domain_established)
+           !z90crypt.domain_established) {
                rv = probe_crypto_domain(cdx_p);
-       if (z90crypt.terminating)
-               return TSQ_FATAL_ERROR;
-       if (rv) {
-               switch (rv) {
-               case Z90C_AMBIGUOUS_DOMAIN:
-                       PRINTK("ambiguous domain detected\n");
-                       break;
-               case Z90C_INCORRECT_DOMAIN:
-                       PRINTK("incorrect domain specified\n");
-                       break;
-               default:
-                       PRINTK("probe domain returned %d\n", rv);
-                       break;
-               }
-               return rv;
-       }
-       if (*cdx_p) {
+               if (z90crypt.terminating)
+                       return TSQ_FATAL_ERROR;
+               if (rv == Z90C_NO_DEVICES)
+                       return 0; // try later
+               if (rv)
+                       return rv;
                z90crypt.cdx = *cdx_p;
                z90crypt.domain_established = 1;
        }
@@ -2999,14 +3154,28 @@ create_crypto_device(int index)
                                return rv;
                        }
                }
+               if (dev_ptr->dev_type == PCIXCC_UNK) {
+                       rv = probe_PCIXCC_type(dev_ptr);
+                       if (rv) {
+                               PRINTK("rv = %d from probe_PCIXCC_type %d\n",
+                                      rv, index);
+                               kfree(dev_ptr->dev_resp_p);
+                               kfree(dev_ptr);
+                               return rv;
+                       }
+               }
                deviceType = dev_ptr->dev_type;
                z90crypt.dev_type_array[index] = deviceType;
                if (deviceType == PCICA)
                        z90crypt.hdware_info->device_type_array[index] = 1;
                else if (deviceType == PCICC)
                        z90crypt.hdware_info->device_type_array[index] = 2;
-               else if (deviceType == PCIXCC)
+               else if (deviceType == PCIXCC_MCL2)
                        z90crypt.hdware_info->device_type_array[index] = 3;
+               else if (deviceType == PCIXCC_MCL3)
+                       z90crypt.hdware_info->device_type_array[index] = 4;
+               else if (deviceType == CEX2C)
+                       z90crypt.hdware_info->device_type_array[index] = 5;
                else
                        z90crypt.hdware_info->device_type_array[index] = -1;
        }
@@ -3086,7 +3255,7 @@ destroy_z90crypt(void)
        memset((void *)&z90crypt, 0, sizeof(z90crypt));
 }
 
-static unsigned char static_testmsg[] = {
+static unsigned char static_testmsg[384] = {
 0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x00,0x06,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x43,0x43,
@@ -3118,7 +3287,7 @@ probe_device_type(struct device *devPtr)
 {
        int rv, dv, i, index, length;
        unsigned char psmid[8];
-       static unsigned char loc_testmsg[384];
+       static unsigned char loc_testmsg[sizeof(static_testmsg)];
 
        index = devPtr->dev_self_x;
        rv = 0;
@@ -3212,8 +3381,146 @@ probe_device_type(struct device *devPtr)
        return rv;
 }
 
+static unsigned char MCL3_testmsg[] = {
+0x00,0x00,0x00,0x00,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
+0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
+0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
+0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
+0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
+0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
+0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
+0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
+0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
+0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
+0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
+0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
+0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
+0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
+0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
+0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,0xF1,0x3D,0x93,0x53
+};
+
+static int
+probe_PCIXCC_type(struct device *devPtr)
+{
+       int rv, dv, i, index, length;
+       unsigned char psmid[8];
+       static unsigned char loc_testmsg[548];
+       struct CPRBX *cprbx_p;
+
+       index = devPtr->dev_self_x;
+       rv = 0;
+       do {
+               memcpy(loc_testmsg, MCL3_testmsg, sizeof(MCL3_testmsg));
+               length = sizeof(MCL3_testmsg) - 0x0C;
+               dv = send_to_AP(index, z90crypt.cdx, length, loc_testmsg);
+               if (dv) {
+                       PDEBUG("dv returned = %d\n", dv);
+                       if (dv == DEV_SEN_EXCEPTION) {
+                               rv = SEN_FATAL_ERROR;
+                               PRINTKC("exception in send to AP %d\n", index);
+                               break;
+                       }
+                       PDEBUG("return value from send_to_AP: %d\n", rv);
+                       switch (dv) {
+                       case DEV_GONE:
+                               PDEBUG("dev %d not available\n", index);
+                               rv = SEN_NOT_AVAIL;
+                               break;
+                       case DEV_ONLINE:
+                               rv = 0;
+                               break;
+                       case DEV_EMPTY:
+                               rv = SEN_NOT_AVAIL;
+                               break;
+                       case DEV_NO_WORK:
+                               rv = SEN_FATAL_ERROR;
+                               break;
+                       case DEV_BAD_MESSAGE:
+                               rv = SEN_USER_ERROR;
+                               break;
+                       case DEV_QUEUE_FULL:
+                               rv = SEN_QUEUE_FULL;
+                               break;
+                       default:
+                               PRINTK("unknown dv=%d for dev %d\n", dv, index);
+                               rv = SEN_NOT_AVAIL;
+                               break;
+                       }
+               }
+
+               if (rv)
+                       break;
+
+               for (i = 0; i < 6; i++) {
+                       mdelay(300);
+                       dv = receive_from_AP(index, z90crypt.cdx,
+                                            devPtr->dev_resp_l,
+                                            devPtr->dev_resp_p, psmid);
+                       PDEBUG("dv returned by DQ = %d\n", dv);
+                       if (dv == DEV_REC_EXCEPTION) {
+                               rv = REC_FATAL_ERROR;
+                               PRINTKC("exception in dequeue %d\n",
+                                       index);
+                               break;
+                       }
+                       switch (dv) {
+                       case DEV_ONLINE:
+                               rv = 0;
+                               break;
+                       case DEV_EMPTY:
+                               rv = REC_EMPTY;
+                               break;
+                       case DEV_NO_WORK:
+                               rv = REC_NO_WORK;
+                               break;
+                       case DEV_BAD_MESSAGE:
+                       case DEV_GONE:
+                       default:
+                               rv = REC_NO_RESPONSE;
+                               break;
+                       }
+                       if ((rv != 0) && (rv != REC_NO_WORK))
+                               break;
+                       if (rv == 0)
+                               break;
+               }
+               if (rv)
+                       break;
+               cprbx_p = (struct CPRBX *) (devPtr->dev_resp_p + 48);
+               if ((cprbx_p->ccp_rtcode == 8) && (cprbx_p->ccp_rscode == 33)) {
+                       devPtr->dev_type = PCIXCC_MCL2;
+                       PDEBUG("device %d is MCL2\n", index);
+               } else {
+                       devPtr->dev_type = PCIXCC_MCL3;
+                       PDEBUG("device %d is MCL3\n", index);
+               }
+       } while (0);
+       /* In a general error case, the card is not marked online */
+       return rv;
+}
+
 #ifdef Z90CRYPT_USE_HOTPLUG
-void
+static void
 z90crypt_hotplug_event(int dev_major, int dev_minor, int action)
 {
 #ifdef CONFIG_HOTPLUG
@@ -3241,6 +3548,7 @@ z90crypt_hotplug_event(int dev_major, int dev_minor, int action)
                break;
        default:
                BUG();
+               break;
        }
        envp[3] = major;
        envp[4] = minor;
index 5c0b29a..1983302 100644 (file)
@@ -63,7 +63,7 @@
                debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
        } while (0)
 
-extern DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf);
+DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
 
 #define IUCV_DBF_TEXT_(name,level,text...)                             \
        do {                                                            \
@@ -231,7 +231,10 @@ typedef struct {
        uchar iptype;
        u32 ipmsgid;
        u32 iptrgcls;
-       uchar iprmmsg1[4];
+       union u2 {
+               u32 iprmmsg1_u32;
+               uchar iprmmsg1[4];
+       } ln1msg1;
        union u1 {
                u32 ipbfln1f;
                uchar iprmmsg2[4];
index 3ad0ace..5889956 100644 (file)
@@ -11,7 +11,9 @@
  *            Aron Zeh
  *            Wolfgang Taphorn
  *            Stefan Bader <stefan.bader@de.ibm.com> 
- *            Heiko Carstens <heiko.carstens@de.ibm.com> 
+ *            Heiko Carstens <heiko.carstens@de.ibm.com>
+ *            Andreas Herrmann <aherrman@de.ibm.com>
+ *            Volker Sameske <sameske@de.ibm.com>
  * 
  * This program is free software; you can redistribute it and/or modify 
  * it under the terms of the GNU General Public License as published by 
 #define FSF_PAYLOAD_SIZE_MISMATCH              0x00000060
 #define FSF_REQUEST_SIZE_TOO_LARGE             0x00000061
 #define FSF_RESPONSE_SIZE_TOO_LARGE            0x00000062
+#define FSF_SBAL_MISMATCH                      0x00000063
+#define FSF_OPEN_PORT_WITHOUT_PRLI             0x00000064
 #define FSF_ADAPTER_STATUS_AVAILABLE           0x000000AD
 #define FSF_FCP_RSP_AVAILABLE                  0x000000AF
 #define FSF_UNKNOWN_COMMAND                    0x000000E2
 /* status types in status read buffer */
 #define FSF_STATUS_READ_PORT_CLOSED            0x00000001
 #define FSF_STATUS_READ_INCOMING_ELS           0x00000002
+#define FSF_STATUS_READ_SENSE_DATA_AVAIL        0x00000003
 #define FSF_STATUS_READ_BIT_ERROR_THRESHOLD    0x00000004
 #define FSF_STATUS_READ_LINK_DOWN              0x00000005 /* FIXME: really? */
 #define FSF_STATUS_READ_LINK_UP                0x00000006
 /* channel features */
 #define FSF_FEATURE_QTCB_SUPPRESSION            0x00000001
 #define FSF_FEATURE_CFDC                       0x00000002
+#define FSF_FEATURE_LUN_SHARING                        0x00000004
 #define FSF_FEATURE_HBAAPI_MANAGEMENT           0x00000010
 #define FSF_FEATURE_ELS_CT_CHAINED_SBALS        0x00000020
 
 /* option */
 #define FSF_OPEN_LUN_SUPPRESS_BOXING           0x00000001
+#define FSF_OPEN_LUN_REPLICATE_SENSE           0x00000002
 
 /* adapter types */
 #define FSF_ADAPTER_TYPE_FICON                  0x00000001
 #define FSF_IOSTAT_FABRIC_RJT                  0x00000005
 #define FSF_IOSTAT_LS_RJT                      0x00000009
 
+/* open LUN access flags*/
+#define FSF_UNIT_ACCESS_OPEN_LUN_ALLOWED       0x01000000
+#define FSF_UNIT_ACCESS_EXCLUSIVE              0x02000000
+#define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER      0x10000000
+
 struct fsf_queue_designator;
 struct fsf_status_read_buffer;
 struct fsf_port_closed_payload;
@@ -378,7 +390,8 @@ struct fsf_qtcb_bottom_support {
        u32 service_class;
        u8  res3[3];
        u8  timeout;
-       u8  res4[184];
+        u32 lun_access_info;
+        u8  res4[180];
        u32 els1_length;
        u32 els2_length;
        u32 req_buf_length;
index 1ff81be..a433252 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/kdebug.h>
 #include <asm/sbus.h>
 #include <asm/uaccess.h>
@@ -1550,7 +1550,7 @@ static void aurora_close(struct tty_struct * tty, struct file * filp)
 #endif
 }
 
-static int aurora_write(struct tty_struct * tty, int from_user, 
+static int aurora_write(struct tty_struct * tty, 
                        const unsigned char *buf, int count)
 {
        struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
@@ -1573,51 +1573,22 @@ static int aurora_write(struct tty_struct * tty, int from_user,
                return 0;
 
        save_flags(flags);
-       if (from_user) {
-               down(&tmp_buf_sem);
-               while (1) {
-                       c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                          SERIAL_XMIT_SIZE - port->xmit_head));
-                       if (c <= 0)
-                               break;
-
-                       c -= copy_from_user(tmp_buf, buf, c);
-                       if (!c) {
-                               if (!total)
-                                       total = -EFAULT;
-                               break;
-                       }
-                       cli();
-                       c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                      SERIAL_XMIT_SIZE - port->xmit_head));
-                       memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
-                       port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-                       port->xmit_cnt += c;
+       while (1) {
+               cli();
+               c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+                                  SERIAL_XMIT_SIZE - port->xmit_head));
+               if (c <= 0) {
                        restore_flags(flags);
-
-                       buf += c;
-                       count -= c;
-                       total += c;
+                       break;
                }
-               up(&tmp_buf_sem);
-       } else {
-               while (1) {
-                       cli();
-                       c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                          SERIAL_XMIT_SIZE - port->xmit_head));
-                       if (c <= 0) {
-                               restore_flags(flags);
-                               break;
-                       }
-                       memcpy(port->xmit_buf + port->xmit_head, buf, c);
-                       port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-                       port->xmit_cnt += c;
-                       restore_flags(flags);
+               memcpy(port->xmit_buf + port->xmit_head, buf, c);
+               port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+               port->xmit_cnt += c;
+               restore_flags(flags);
 
-                       buf += c;
-                       count -= c;
-                       total += c;
-               }
+               buf += c;
+               count -= c;
+               total += c;
        }
 
        cli();
@@ -2368,10 +2339,10 @@ int irq  = 0;
 int irq1 = 0;
 int irq2 = 0;
 int irq3 = 0;
-MODULE_PARM(irq , "i");
-MODULE_PARM(irq1, "i");
-MODULE_PARM(irq2, "i");
-MODULE_PARM(irq3, "i");
+module_param(irq , int, 0);
+module_param(irq1, int, 0);
+module_param(irq2, int, 0);
+module_param(irq3, int, 0);
 
 static int __init aurora_init(void) 
 {
index 2dcd3cd..1c8b612 100644 (file)
@@ -57,8 +57,8 @@ struct bbc_i2c_bus {
        struct bbc_i2c_bus              *next;
        int                             index;
        spinlock_t                      lock;
-       void                            *i2c_bussel_reg;
-       void                            *i2c_control_regs;
+       void                            __iomem *i2c_bussel_reg;
+       void                            __iomem *i2c_control_regs;
        unsigned char                   own, clock;
 
        wait_queue_head_t               wq;
index 399c6c7..0b886c6 100644 (file)
@@ -21,7 +21,7 @@
  * as a silly safeguard.
  *
  * XXX The flash.c manipulates page caching characteristics in a certain
- * dubious way; also it assumes that remap_page_range() can remap
+ * dubious way; also it assumes that remap_pfn_range() can remap
  * PCI bus locations, which may be false. ioremap() must be used
  * instead. We should discuss this.
  */
index 2bac40c..1996985 100644 (file)
@@ -1746,6 +1746,7 @@ static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
                twa_free_request_id(tw_dev, request_id);
                SCpnt->result = (DID_ERROR << 16);
                done(SCpnt);
+               retval = 0;
        }
 
        return retval;
index 3c91ce6..29f70d5 100644 (file)
@@ -453,13 +453,13 @@ static twa_message_type twa_error_table[] = {
 
 /* Macros */
 #define TW_CONTROL_REG_ADDR(x) (x->base_addr)
-#define TW_STATUS_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x4)
+#define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x4)
 #if BITS_PER_LONG > 32
-#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x20)
+#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x20)
 #else
-#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x8)
+#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x8)
 #endif
-#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0xC)
+#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0xC)
 #define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
 #define TW_CLEAR_ATTENTION_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
 #define TW_CLEAR_HOST_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
@@ -655,7 +655,7 @@ typedef struct TAG_TW_Compatibility_Info
 } TW_Compatibility_Info;
 
 typedef struct TAG_TW_Device_Extension {
-       u32                     *base_addr;
+       u32                     __iomem *base_addr;
        unsigned long           *generic_buffer_virt[TW_Q_LENGTH];
        unsigned long           generic_buffer_phys[TW_Q_LENGTH];
        TW_Command_Full         *command_packet_virt[TW_Q_LENGTH];
index facbce6..1aaa656 100644 (file)
@@ -1098,7 +1098,7 @@ struct BusLogic_HostAdapter {
        struct BusLogic_DriverOptions *DriverOptions;
        struct FlashPoint_Info FlashPointInfo;
        FlashPoint_CardHandle_T CardHandle;
-       struct BusLogic_HostAdapter *Next;
+       struct list_head host_list;
        struct BusLogic_CCB *All_CCBs;
        struct BusLogic_CCB *Free_CCBs;
        struct BusLogic_CCB *FirstCompletedCCB;
@@ -1169,46 +1169,6 @@ struct SCSI_Inquiry {
        unsigned char ProductRevisionLevel[4];  /* Bytes 32-35 */
 };
 
-/*
-  BusLogic_AcquireHostAdapterLock acquires exclusive access to Host Adapter.
-*/
-
-static inline void BusLogic_AcquireHostAdapterLock(struct BusLogic_HostAdapter *HostAdapter)
-{
-       spin_lock_irq(HostAdapter->SCSI_Host->host_lock);
-}
-
-/*
-  BusLogic_ReleaseHostAdapterLock releases exclusive access to Host Adapter.
-*/
-
-static inline void BusLogic_ReleaseHostAdapterLock(struct BusLogic_HostAdapter *HostAdapter)
-{
-       spin_unlock_irq(HostAdapter->SCSI_Host->host_lock);
-}
-
-
-/*
-  BusLogic_AcquireHostAdapterLockIH acquires exclusive access to Host Adapter,
-  but is only called from the interrupt handler.
-*/
-
-static inline void BusLogic_AcquireHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, unsigned long *ProcessorFlags)
-{
-       spin_lock_irqsave(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
-}
-
-
-/*
-  BusLogic_ReleaseHostAdapterLockIH releases exclusive access to Host Adapter,
-  but is only called from the interrupt handler.
-*/
-
-static inline void BusLogic_ReleaseHostAdapterLockIH(struct BusLogic_HostAdapter *HostAdapter, unsigned long *ProcessorFlags)
-{
-       spin_unlock_irqrestore(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
-}
-
 
 /*
   Define functions to provide an abstraction for reading and writing the
@@ -1386,8 +1346,6 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T Co
 */
 
 static const char *BusLogic_DriverInfo(struct Scsi_Host *);
-static int BusLogic_DetectHostAdapter(struct scsi_host_template *);
-static int BusLogic_ReleaseHostAdapter(struct Scsi_Host *);
 static int BusLogic_QueueCommand(struct scsi_cmnd *, void (*CompletionRoutine) (struct scsi_cmnd *));
 static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *);
 static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int);
index 2032b62..6b3d2b2 100644 (file)
 
 /*
  * Design
- * Issues :
  *
- * The other Linux SCSI drivers were written when Linux was Intel PC-only,
- * and specifically for each board rather than each chip.  This makes their
- * adaptation to platforms like the Mac (Some of which use NCR5380's)
- * more difficult than it has to be.
- *
- * Also, many of the SCSI drivers were written before the command queuing
- * routines were implemented, meaning their implementations of queued 
- * commands were hacked on rather than designed in from the start.
- *
- * When I designed the Linux SCSI drivers I figured that 
- * while having two different SCSI boards in a system might be useful
- * for debugging things, two of the same type wouldn't be used.
- * Well, I was wrong and a number of users have mailed me about running
- * multiple high-performance SCSI boards in a server.
- *
- * Finally, when I get questions from users, I have no idea what 
- * revision of my driver they are running.
- *
- * This driver attempts to address these problems :
  * This is a generic 5380 driver.  To use it on a different platform, 
  * one simply writes appropriate system specific macros (ie, data
  * transfer - some PC's will use the I/O bus, 68K's must use 
  * memory mapped) and drops this file in their 'C' wrapper.
  *
+ * (Note from hch:  unfortunately it was not enough for the different
+ * m68k folks and instead of improving this driver they copied it
+ * and hacked it up for their needs.  As a consequence they lost
+ * most updates to this driver.  Maybe someone will fix all these
+ * drivers to use a common core one day..)
+ *
  * As far as command queueing, two queues are maintained for 
  * each 5380 in the system - commands that haven't been issued yet,
  * and commands that are currently executing.  This means that an 
  * allowing multiple commands to propagate all the way to a SCSI-II device 
  * while a command is already executing.
  *
- * To solve the multiple-boards-in-the-same-system problem, 
- * there is a separate instance structure for each instance
- * of a 5380 in the system.  So, multiple NCR5380 drivers will
- * be able to coexist with appropriate changes to the high level
- * SCSI code.  
- *
- * A NCR5380_PUBLIC_REVISION macro is provided, with the release
- * number (updated for each public release) printed by the 
- * NCR5380_print_options command, which should be called from the 
- * wrapper detect function, so that I know what release of the driver
- * users are using.
  *
  * Issues specific to the NCR5380 : 
  *
  * Architecture :
  *
  * At the heart of the design is a coroutine, NCR5380_main,
- * which is started when not running by the interrupt handler,
- * timer, and queue command function.  It attempts to establish
- * I_T_L or I_T_L_Q nexuses by removing the commands from the 
- * issue queue and calling NCR5380_select() if a nexus 
- * is not established. 
+ * which is started from a workqueue for each NCR5380 host in the
+ * system.  It attempts to establish I_T_L or I_T_L_Q nexuses by
+ * removing the commands from the issue queue and calling
+ * NCR5380_select() if a nexus is not established. 
  *
  * Once a nexus is established, the NCR5380_information_transfer()
  * phase goes through the various phases as instructed by the target.
  * NCR5380_pwrite(instance, src, count)
  * NCR5380_pread(instance, dst, count);
  *
- * If nothing specific to this implementation needs doing (ie, with external
- * hardware), you must also define 
- *  
- * NCR5380_queue_command
- * NCR5380_reset
- * NCR5380_abort
- * NCR5380_proc_info
- *
- * to be the global entry points into the specific driver, ie 
- * #define NCR5380_queue_command t128_queue_command.
- *
- * If this is not done, the routines will be defined as static functions
- * with the NCR5380* names and the user must provide a globally
- * accessible wrapper function.
- *
  * The generic driver is initialized by calling NCR5380_init(instance),
  * after setting the appropriate host specific fields and ID.  If the 
  * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
- * possible) function may be used.  Before the specific driver initialization
- * code finishes, NCR5380_print_options should be called.
+ * possible) function may be used.
  */
+
 static int do_abort(struct Scsi_Host *host);
 static void do_reset(struct Scsi_Host *host);
 
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))
index 8dd5d1f..e0cd4ba 100644 (file)
@@ -272,7 +272,7 @@ static void ahci_host_stop(struct ata_host_set *host_set)
 
 static int ahci_port_start(struct ata_port *ap)
 {
-       struct pci_dev *pdev = ap->host_set->pdev;
+       struct device *dev = ap->host_set->dev;
        struct ahci_host_priv *hpriv = ap->host_set->private_data;
        struct ahci_port_priv *pp;
        int rc;
@@ -291,7 +291,7 @@ static int ahci_port_start(struct ata_port *ap)
        }
        memset(pp, 0, sizeof(*pp));
 
-       mem = pci_alloc_consistent(pdev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma);
+       mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
        if (!mem) {
                rc = -ENOMEM;
                goto err_out_kfree;
@@ -355,7 +355,7 @@ err_out:
 
 static void ahci_port_stop(struct ata_port *ap)
 {
-       struct pci_dev *pdev = ap->host_set->pdev;
+       struct device *dev = ap->host_set->dev;
        struct ahci_port_priv *pp = ap->private_data;
        void *mmio = ap->host_set->mmio_base;
        void *port_mmio = ahci_port_base(mmio, ap->port_no);
@@ -372,8 +372,8 @@ static void ahci_port_stop(struct ata_port *ap)
        msleep(500);
 
        ap->private_data = NULL;
-       pci_free_consistent(pdev, AHCI_PORT_PRIV_DMA_SZ,
-                           pp->cmd_slot, pp->cmd_slot_dma);
+       dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
+                         pp->cmd_slot, pp->cmd_slot_dma);
        kfree(pp);
        ata_port_stop(ap);
 }
@@ -705,7 +705,7 @@ static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
 static int ahci_host_init(struct ata_probe_ent *probe_ent)
 {
        struct ahci_host_priv *hpriv = probe_ent->private_data;
-       struct pci_dev *pdev = probe_ent->pdev;
+       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
        void __iomem *mmio = probe_ent->mmio_base;
        u32 tmp, cap_save;
        u16 tmp16;
@@ -863,7 +863,7 @@ static void pci_enable_intx(struct pci_dev *pdev)
 static void ahci_print_info(struct ata_probe_ent *probe_ent)
 {
        struct ahci_host_priv *hpriv = probe_ent->private_data;
-       struct pci_dev *pdev = probe_ent->pdev;
+       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
        void *mmio = probe_ent->mmio_base;
        u32 vers, cap, impl, speed;
        const char *speed_s;
@@ -946,10 +946,6 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!printed_version++)
                printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
 
-       /*
-        * If this driver happens to only be useful on Apple's K2, then
-        * we should check that here as it has a normal Serverworks ID
-        */
        rc = pci_enable_device(pdev);
        if (rc)
                return rc;
@@ -967,7 +963,7 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        memset(probe_ent, 0, sizeof(*probe_ent));
-       probe_ent->pdev = pdev;
+       probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
        mmio_base = ioremap(pci_resource_start(pdev, AHCI_PCI_BAR),
@@ -1039,7 +1035,6 @@ MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("AHCI SATA low-level driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
 
 module_init(ahci_init);
 module_exit(ahci_exit);
index be65968..fd4b2f3 100644 (file)
@@ -549,7 +549,7 @@ struct ahd_dma64_seg {
 
 struct map_node {
        bus_dmamap_t             dmamap;
-       bus_addr_t               physaddr;
+       dma_addr_t               physaddr;
        uint8_t                 *vaddr;
        SLIST_ENTRY(map_node)    links;
 };
@@ -626,8 +626,8 @@ struct scb {
        struct map_node          *sense_map;
        void                     *sg_list;
        uint8_t                  *sense_data;
-       bus_addr_t                sg_list_busaddr;
-       bus_addr_t                sense_busaddr;
+       dma_addr_t                sg_list_busaddr;
+       dma_addr_t                sense_busaddr;
        u_int                     sg_count;/* How full ahd_dma_seg is */
 #define        AHD_MAX_LQ_CRC_ERRORS 5
        u_int                     crc_retry_count;
@@ -1198,7 +1198,7 @@ struct ahd_softc {
        bus_dma_tag_t             parent_dmat;
        bus_dma_tag_t             shared_data_dmat;
        bus_dmamap_t              shared_data_dmamap;
-       bus_addr_t                shared_data_busaddr;
+       dma_addr_t                shared_data_busaddr;
 
        /* Information saved through suspend/resume cycles */
        struct ahd_suspend_state  suspend_state;
index 449fe95..cca58ed 100644 (file)
@@ -1199,7 +1199,7 @@ register TARGPCISTAT {
 
 /*
  * LQ Packet In
- * The last LQ Packet recieved
+ * The last LQ Packet received
  */
 register LQIN {
        address                 0x020
index 440212a..d80bc51 100644 (file)
@@ -231,7 +231,7 @@ ahd_unpause(struct ahd_softc *ahd)
 
 /*********************** Scatter Gather List Handling *************************/
 static __inline void   *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
-                                     void *sgptr, bus_addr_t addr,
+                                     void *sgptr, dma_addr_t addr,
                                      bus_size_t len, int last);
 static __inline void    ahd_setup_scb_common(struct ahd_softc *ahd,
                                              struct scb *scb);
@@ -242,10 +242,10 @@ static __inline void       ahd_setup_noxfer_scb(struct ahd_softc *ahd,
 
 static __inline void *
 ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
-            void *sgptr, bus_addr_t addr, bus_size_t len, int last)
+            void *sgptr, dma_addr_t addr, bus_size_t len, int last)
 {
        scb->sg_count++;
-       if (sizeof(bus_addr_t) > 4
+       if (sizeof(dma_addr_t) > 4
         && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
                struct ahd_dma64_seg *sg;
 
@@ -361,7 +361,7 @@ ahd_sg_size(struct ahd_softc *ahd)
 static __inline void *
 ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
 {
-       bus_addr_t sg_offset;
+       dma_addr_t sg_offset;
 
        /* sg_list_phys points to entry 1, not 0 */
        sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd));
@@ -371,7 +371,7 @@ ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
 static __inline uint32_t
 ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg)
 {
-       bus_addr_t sg_offset;
+       dma_addr_t sg_offset;
 
        /* sg_list_phys points to entry 1, not 0 */
        sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list)
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_ */
index ef1214c..8ff16fd 100644 (file)
@@ -521,7 +521,7 @@ struct ahc_dma_seg {
 
 struct sg_map_node {
        bus_dmamap_t             sg_dmamap;
-       bus_addr_t               sg_physaddr;
+       dma_addr_t               sg_physaddr;
        struct ahc_dma_seg*      sg_vaddr;
        SLIST_ENTRY(sg_map_node) links;
 };
@@ -584,7 +584,7 @@ struct scb {
        struct scb_platform_data *platform_data;
        struct sg_map_node       *sg_map;
        struct ahc_dma_seg       *sg_list;
-       bus_addr_t                sg_list_phys;
+       dma_addr_t                sg_list_phys;
        u_int                     sg_count;/* How full ahc_dma_seg is */
 };
 
@@ -611,10 +611,10 @@ struct scb_data {
         */
        bus_dma_tag_t    hscb_dmat;     /* dmat for our hardware SCB array */
        bus_dmamap_t     hscb_dmamap;
-       bus_addr_t       hscb_busaddr;
+       dma_addr_t       hscb_busaddr;
        bus_dma_tag_t    sense_dmat;
        bus_dmamap_t     sense_dmamap;
-       bus_addr_t       sense_busaddr;
+       dma_addr_t       sense_busaddr;
        bus_dma_tag_t    sg_dmat;       /* dmat for our sg segments */
        SLIST_HEAD(, sg_map_node) sg_maps;
        uint8_t numscbs;
@@ -1069,14 +1069,14 @@ struct ahc_softc {
        bus_dma_tag_t             parent_dmat;
        bus_dma_tag_t             shared_data_dmat;
        bus_dmamap_t              shared_data_dmamap;
-       bus_addr_t                shared_data_busaddr;
+       dma_addr_t                shared_data_busaddr;
 
        /*
         * Bus address of the one byte buffer used to
         * work-around a DMA bug for chips <= aic7880
         * in target mode.
         */
-       bus_addr_t                dma_bug_buf;
+       dma_addr_t                dma_bug_buf;
 
        /* Number of enabled target mode device on this card */
        u_int                     enabled_luns;
index 476780b..e3b50fc 100644 (file)
@@ -54,8 +54,7 @@
 #include <dev/aic7xxx/aic7xxx_93cx6.h>
 #endif
 
-#define AHC_PCI_IOADDR PCIR_MAPS       /* I/O Address */
-#define AHC_PCI_MEMADDR        (PCIR_MAPS + 4) /* Mem I/O Address */
+#include "aic7xxx_pci.h"
 
 static __inline uint64_t
 ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
@@ -70,84 +69,8 @@ ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
        return (id);
 }
 
-#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
+#define AHC_PCI_IOADDR PCIR_MAPS       /* I/O Address */
+#define AHC_PCI_MEMADDR        (PCIR_MAPS + 4) /* Mem I/O Address */
 
 #define DEVID_9005_TYPE(id) ((id) & 0xF)
 #define                DEVID_9005_TYPE_HBA             0x0     /* Standard Card */
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_ */
index a0243ee..bfe6f95 100644 (file)
@@ -1043,4 +1043,43 @@ scsi_4btoul(uint8_t *bytes)
        return (rv);
 }
 
+/* Macros for generating the elements of the PCI ID tables. */
+
+#define GETID(v, s) (unsigned)(((v) >> (s)) & 0xFFFF ?: PCI_ANY_ID)
+
+#define ID_C(x, c)                                             \
+{                                                              \
+       GETID(x,32), GETID(x,48), GETID(x,0), GETID(x,16),      \
+       (c) << 8, 0xFFFF00, 0                                   \
+}
+
+#define ID2C(x)                          \
+       ID_C(x, PCI_CLASS_STORAGE_SCSI), \
+       ID_C(x, PCI_CLASS_STORAGE_RAID)
+
+#define IDIROC(x)  ((x) | ~ID_ALL_IROC_MASK)
+
+/* Generate IDs for all 16 possibilites.
+ * The argument has already masked out
+ * the 4 least significant bits of the device id.
+ * (e.g., mask: ID_9005_GENERIC_MASK).
+ */
+#define ID16(x)                          \
+       ID(x),                           \
+       ID((x) | 0x0001000000000000ull), \
+       ID((x) | 0x0002000000000000ull), \
+       ID((x) | 0x0003000000000000ull), \
+       ID((x) | 0x0004000000000000ull), \
+       ID((x) | 0x0005000000000000ull), \
+       ID((x) | 0x0006000000000000ull), \
+       ID((x) | 0x0007000000000000ull), \
+       ID((x) | 0x0008000000000000ull), \
+       ID((x) | 0x0009000000000000ull), \
+       ID((x) | 0x000A000000000000ull), \
+       ID((x) | 0x000B000000000000ull), \
+       ID((x) | 0x000C000000000000ull), \
+       ID((x) | 0x000D000000000000ull), \
+       ID((x) | 0x000E000000000000ull), \
+       ID((x) | 0x000F000000000000ull)
+
 #endif /*_AICLIB_H */
index b9ba333..d40ba07 100644 (file)
@@ -85,12 +85,6 @@ typedef enum {
        CAM_STATUS_MASK         = 0x3F
 } cam_status;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-#define        SCSI_DATA_READ  1
-#define        SCSI_DATA_WRITE 2
-#define SCSI_DATA_NONE  3
-#endif
-
 /*
  * Definitions for the asynchronous callback CCB fields.
  */
index e15d821..c4bcdbf 100644 (file)
@@ -46,40 +46,40 @@ static int dtc_host_reset(Scsi_Cmnd *);
 #endif
 
 #define NCR5380_implementation_fields \
-    unsigned int base
+    void __iomem *base
 
 #define NCR5380_local_declare() \
-    unsigned int base
+    void __iomem *base
 
 #define NCR5380_setup(instance) \
-    base = (unsigned int)(instance)->base
+    base = ((struct NCR5380_hostdata *)(instance)->hostdata)->base
 
 #define DTC_address(reg) (base + DTC_5380_OFFSET + reg)
 
 #define dbNCR5380_read(reg)                                              \
-    (rval=isa_readb(DTC_address(reg)), \
-     (((unsigned char) printk("DTC : read register %d at addr %08x is: %02x\n"\
-    , (reg), (int)DTC_address(reg), rval)), rval ) )
+    (rval=readb(DTC_address(reg)), \
+     (((unsigned char) printk("DTC : read register %d at addr %p is: %02x\n"\
+    , (reg), DTC_address(reg), rval)), rval ) )
 
 #define dbNCR5380_write(reg, value) do {                                  \
-    printk("DTC : write %02x to register %d at address %08x\n",         \
-            (value), (reg), (int)DTC_address(reg));     \
-    isa_writeb(value, DTC_address(reg));} while(0)
+    printk("DTC : write %02x to register %d at address %p\n",         \
+            (value), (reg), DTC_address(reg));     \
+    writeb(value, DTC_address(reg));} while(0)
 
 
 #if !(DTCDEBUG & DTCDEBUG_TRANSFER) 
-#define NCR5380_read(reg) (isa_readb(DTC_address(reg)))
-#define NCR5380_write(reg, value) (isa_writeb(value, DTC_address(reg)))
+#define NCR5380_read(reg) (readb(DTC_address(reg)))
+#define NCR5380_write(reg, value) (writeb(value, DTC_address(reg)))
 #else
-#define NCR5380_read(reg) (isa_readb(DTC_address(reg)))
+#define NCR5380_read(reg) (readb(DTC_address(reg)))
 #define xNCR5380_read(reg)                                             \
-    (((unsigned char) printk("DTC : read register %d at address %08x\n"\
-    , (reg), DTC_address(reg))), isa_readb(DTC_address(reg)))
+    (((unsigned char) printk("DTC : read register %d at address %p\n"\
+    , (reg), DTC_address(reg))), readb(DTC_address(reg)))
 
 #define NCR5380_write(reg, value) do {                                 \
-    printk("DTC : write %02x to register %d at address %08x\n",        \
-           (value), (reg), (int)DTC_address(reg));     \
-    isa_writeb(value, DTC_address(reg));} while(0)
+    printk("DTC : write %02x to register %d at address %p\n",  \
+           (value), (reg), DTC_address(reg));  \
+    writeb(value, DTC_address(reg));} while(0)
 #endif
 
 #define NCR5380_intr                   dtc_intr
index b4e8265..50cb909 100644 (file)
@@ -204,7 +204,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        }
 
        queue->cur = 0;
-       queue->lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&queue->lock);
 
        tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
                     (unsigned long)hostdata);
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[];
index 40bfff7..923dcf9 100644 (file)
@@ -4935,7 +4935,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
        int rc;
 
        ENTER;
-       rc = pci_restore_state(ioa_cfg->pdev, ioa_cfg->pci_cfg_buf);
+       rc = pci_restore_state(ioa_cfg->pdev);
 
        if (rc != PCIBIOS_SUCCESSFUL) {
                ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
@@ -5433,7 +5433,7 @@ static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg)
 
        ENTER;
        free_irq(pdev->irq, ioa_cfg);
-       iounmap((void *) ioa_cfg->hdw_dma_regs);
+       iounmap(ioa_cfg->hdw_dma_regs);
        pci_release_regions(pdev);
        ipr_free_mem(ioa_cfg);
        scsi_host_put(ioa_cfg->host);
@@ -5624,6 +5624,10 @@ static void __devinit ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
 static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
                                       struct Scsi_Host *host, struct pci_dev *pdev)
 {
+       const struct ipr_interrupt_offsets *p;
+       struct ipr_interrupts *t;
+       void __iomem *base;
+
        ioa_cfg->host = host;
        ioa_cfg->pdev = pdev;
        ioa_cfg->log_level = ipr_log_level;
@@ -5655,17 +5659,19 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
        host->max_cmd_len = IPR_MAX_CDB_LEN;
        pci_set_drvdata(pdev, ioa_cfg);
 
-       memcpy(&ioa_cfg->regs, &ioa_cfg->chip_cfg->regs, sizeof(ioa_cfg->regs));
+       p = &ioa_cfg->chip_cfg->regs;
+       t = &ioa_cfg->regs;
+       base = ioa_cfg->hdw_dma_regs;
 
-       ioa_cfg->regs.set_interrupt_mask_reg += ioa_cfg->hdw_dma_regs;
-       ioa_cfg->regs.clr_interrupt_mask_reg += ioa_cfg->hdw_dma_regs;
-       ioa_cfg->regs.sense_interrupt_mask_reg += ioa_cfg->hdw_dma_regs;
-       ioa_cfg->regs.clr_interrupt_reg += ioa_cfg->hdw_dma_regs;
-       ioa_cfg->regs.sense_interrupt_reg += ioa_cfg->hdw_dma_regs;
-       ioa_cfg->regs.ioarrin_reg += ioa_cfg->hdw_dma_regs;
-       ioa_cfg->regs.sense_uproc_interrupt_reg += ioa_cfg->hdw_dma_regs;
-       ioa_cfg->regs.set_uproc_interrupt_reg += ioa_cfg->hdw_dma_regs;
-       ioa_cfg->regs.clr_uproc_interrupt_reg += ioa_cfg->hdw_dma_regs;
+       t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
+       t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
+       t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
+       t->clr_interrupt_reg = base + p->clr_interrupt_reg;
+       t->sense_interrupt_reg = base + p->sense_interrupt_reg;
+       t->ioarrin_reg = base + p->ioarrin_reg;
+       t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
+       t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
+       t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
 }
 
 /**
@@ -5681,7 +5687,8 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
 {
        struct ipr_ioa_cfg *ioa_cfg;
        struct Scsi_Host *host;
-       unsigned long ipr_regs, ipr_regs_pci;
+       unsigned long ipr_regs_pci;
+       void __iomem *ipr_regs;
        u32 rc = PCIBIOS_SUCCESSFUL;
 
        ENTER;
@@ -5715,8 +5722,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
                goto out_scsi_host_put;
        }
 
-       ipr_regs = (unsigned long)ioremap(ipr_regs_pci,
-                                         pci_resource_len(pdev, 0));
+       ipr_regs = ioremap(ipr_regs_pci, pci_resource_len(pdev, 0));
 
        if (!ipr_regs) {
                dev_err(&pdev->dev,
@@ -5749,7 +5755,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        }
 
        /* Save away PCI config space for use following IOA reset */
-       rc = pci_save_state(pdev, ioa_cfg->pci_cfg_buf);
+       rc = pci_save_state(pdev);
 
        if (rc != PCIBIOS_SUCCESSFUL) {
                dev_err(&pdev->dev, "Failed to save PCI config space\n");
@@ -5790,7 +5796,7 @@ out:
 cleanup_nolog:
        ipr_free_mem(ioa_cfg);
 cleanup_nomem:
-       iounmap((void *) ipr_regs);
+       iounmap(ipr_regs);
 out_release_regions:
        pci_release_regions(pdev);
 out_scsi_host_put:
index e91afc4..1a5f247 100644 (file)
@@ -749,7 +749,7 @@ struct ipr_misc_cbs {
        struct ipr_supported_device supp_dev;
 };
 
-struct ipr_interrupts {
+struct ipr_interrupt_offsets {
        unsigned long set_interrupt_mask_reg;
        unsigned long clr_interrupt_mask_reg;
        unsigned long sense_interrupt_mask_reg;
@@ -762,10 +762,23 @@ struct ipr_interrupts {
        unsigned long clr_uproc_interrupt_reg;
 };
 
+struct ipr_interrupts {
+       void __iomem *set_interrupt_mask_reg;
+       void __iomem *clr_interrupt_mask_reg;
+       void __iomem *sense_interrupt_mask_reg;
+       void __iomem *clr_interrupt_reg;
+
+       void __iomem *sense_interrupt_reg;
+       void __iomem *ioarrin_reg;
+       void __iomem *sense_uproc_interrupt_reg;
+       void __iomem *set_uproc_interrupt_reg;
+       void __iomem *clr_uproc_interrupt_reg;
+};
+
 struct ipr_chip_cfg_t {
        u32 mailbox;
        u8 cache_line_size;
-       struct ipr_interrupts regs;
+       struct ipr_interrupt_offsets regs;
 };
 
 enum ipr_shutdown_type {
@@ -884,12 +897,11 @@ struct ipr_ioa_cfg {
 
        const struct ipr_chip_cfg_t *chip_cfg;
 
-       unsigned long hdw_dma_regs;     /* iomapped PCI memory space */
+       void __iomem *hdw_dma_regs;     /* iomapped PCI memory space */
        unsigned long hdw_dma_regs_pci; /* raw PCI memory space */
-       unsigned long ioa_mailbox;
+       void __iomem *ioa_mailbox;
        struct ipr_interrupts regs;
 
-       u32 pci_cfg_buf[64];
        u16 saved_pcix_cmd_reg;
        u16 reset_retries;
 
index 42654a7..3ef2a14 100644 (file)
@@ -41,9 +41,9 @@ enum fsc_phase {
 };
 
 struct fsc_state {
-       struct  mac53c94_regs *regs;
+       struct  mac53c94_regs __iomem *regs;
        int     intr;
-       struct  dbdma_regs *dma;
+       struct  dbdma_regs __iomem *dma;
        int     dmaintr;
        int     clk_freq;
        struct  Scsi_Host *host;
@@ -106,10 +106,10 @@ static int mac53c94_abort(struct scsi_cmnd *cmd)
 static int mac53c94_host_reset(struct scsi_cmnd *cmd)
 {
        struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata;
-       struct mac53c94_regs *regs = state->regs;
-       struct dbdma_regs *dma = state->dma;
+       struct mac53c94_regs __iomem *regs = state->regs;
+       struct dbdma_regs __iomem *dma = state->dma;
 
-       st_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+       writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control);
        writeb(CMD_SCSI_RESET, &regs->command); /* assert RST */
        udelay(100);                    /* leave it on for a while (>= 25us) */
        writeb(CMD_RESET, &regs->command);
@@ -121,8 +121,8 @@ static int mac53c94_host_reset(struct scsi_cmnd *cmd)
 
 static void mac53c94_init(struct fsc_state *state)
 {
-       struct mac53c94_regs *regs = state->regs;
-       struct dbdma_regs *dma = state->dma;
+       struct mac53c94_regs __iomem *regs = state->regs;
+       struct dbdma_regs __iomem *dma = state->dma;
        int x;
 
        writeb(state->host->this_id | CF1_PAR_ENABLE, &regs->config1);
@@ -143,7 +143,7 @@ static void mac53c94_init(struct fsc_state *state)
 static void mac53c94_start(struct fsc_state *state)
 {
        struct scsi_cmnd *cmd;
-       struct mac53c94_regs *regs = state->regs;
+       struct mac53c94_regs __iomem *regs = state->regs;
        int i;
 
        if (state->phase != idle || state->current_req != NULL)
@@ -191,8 +191,8 @@ static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *
 static void mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
        struct fsc_state *state = (struct fsc_state *) dev_id;
-       struct mac53c94_regs *regs = state->regs;
-       struct dbdma_regs *dma = state->dma;
+       struct mac53c94_regs __iomem *regs = state->regs;
+       struct dbdma_regs __iomem *dma = state->dma;
        struct scsi_cmnd *cmd = state->current_req;
        int nb, stat, seq, intr;
        static int mac53c94_errors;
@@ -458,10 +458,10 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_match *match)
        state->pdev = pdev;
        state->mdev = mdev;
 
-       state->regs = (struct mac53c94_regs *)
+       state->regs = (struct mac53c94_regs __iomem *)
                ioremap(macio_resource_start(mdev, 0), 0x1000);
        state->intr = macio_irq(mdev, 0);
-       state->dma = (struct dbdma_regs *)
+       state->dma = (struct dbdma_regs __iomem *)
                ioremap(macio_resource_start(mdev, 1), 0x1000);
        state->dmaintr = macio_irq(mdev, 1);
        if (state->regs == NULL || state->dma == NULL) {
index 44584ca..4bf0430 100644 (file)
@@ -142,9 +142,11 @@ typedef struct uioc {
 
        caddr_t                 buf_vaddr;
        dma_addr_t              buf_paddr;
-       uint8_t                 pool_index;
+       int8_t                  pool_index;
        uint8_t                 free_buf;
 
+       uint8_t                 timedout;
+
 } __attribute__ ((aligned(1024),packed)) uioc_t;
 
 
@@ -247,6 +249,7 @@ typedef struct mm_dmapool {
  * @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)
+ * @quiescent          : flag to indicate if ioctl can be issued to this adp
  * @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
@@ -264,7 +267,7 @@ typedef struct mraid_mmadp {
        uint32_t                unique_id;
        uint32_t                drvr_type;
        unsigned long           drvr_data;
-       uint8_t                 timeout;
+       uint16_t                timeout;
        uint8_t                 max_kioc;
 
        struct pci_dev          *pdev;
@@ -272,6 +275,7 @@ typedef struct mraid_mmadp {
        int(*issue_uioc)(unsigned long, uioc_t *, uint32_t);
 
 /* Maintained by common module */
+       uint32_t                quiescent;
 
        struct list_head        list;
        uioc_t                  *kioc_list;
index 7afd6a5..c38df6c 100644 (file)
@@ -10,7 +10,7 @@
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_mbox.c
- * Version     : v2.20.4 (September 27 2004)
+ * Version     : v2.20.4.1 (Nov 04 2004)
  *
  * Authors:
  *     Atul Mukker             <Atul.Mukker@lsil.com>
@@ -294,6 +294,12 @@ static struct pci_device_id pci_id_table_g[] =  {
                PCI_VENDOR_ID_DELL,
                PCI_SUBSYS_ID_PERC3_SC,
        },
+       {
+               PCI_VENDOR_ID_AMI,
+               PCI_DEVICE_ID_AMI_MEGARAID3,
+               PCI_VENDOR_ID_AMI,
+               PCI_SUBSYS_ID_PERC3_SC,
+       },
        {
                PCI_VENDOR_ID_LSI_LOGIC,
                PCI_DEVICE_ID_MEGARAID_SCSI_320_0,
@@ -872,8 +878,7 @@ megaraid_init_mbox(adapter_t *adapter)
                goto out_free_raid_dev;
        }
 
-       raid_dev->baseaddr = (unsigned long)
-                       ioremap_nocache(raid_dev->baseport, 128);
+       raid_dev->baseaddr = ioremap_nocache(raid_dev->baseport, 128);
 
        if (!raid_dev->baseaddr) {
 
@@ -996,7 +1001,7 @@ out_alloc_cmds:
 out_free_irq:
        free_irq(adapter->irq, adapter);
 out_iounmap:
-       iounmap((caddr_t)raid_dev->baseaddr);
+       iounmap(raid_dev->baseaddr);
 out_release_regions:
        pci_release_regions(pdev);
 out_free_raid_dev:
@@ -1024,7 +1029,7 @@ megaraid_fini_mbox(adapter_t *adapter)
 
        free_irq(adapter->irq, adapter);
 
-       iounmap((caddr_t)raid_dev->baseaddr);
+       iounmap(raid_dev->baseaddr);
 
        pci_release_regions(adapter->pdev);
 
@@ -1554,12 +1559,12 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb)
 
        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,
+                       pci_dma_sync_single_for_device(adapter->pdev, ccb->buf_dma_h,
                                        scb->scp->request_bufflen,
                                        PCI_DMA_TODEVICE);
                }
                else {
-                       pci_dma_sync_sg(adapter->pdev, scb->scp->request_buffer,
+                       pci_dma_sync_sg_for_device(adapter->pdev, scb->scp->request_buffer,
                                scb->scp->use_sg, PCI_DMA_TODEVICE);
                }
        }
@@ -1618,6 +1623,7 @@ megaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *))
 
        if (!scb) {     // command already completed
                done(scp);
+               return 0;
        }
 
        return if_busy;
@@ -2332,7 +2338,7 @@ megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
 
        case MRAID_DMA_WBUF:
                if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
-                       pci_dma_sync_single(adapter->pdev,
+                       pci_dma_sync_single_for_cpu(adapter->pdev,
                                        ccb->buf_dma_h,
                                        scb->scp->request_bufflen,
                                        PCI_DMA_FROMDEVICE);
@@ -2345,7 +2351,7 @@ megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
 
        case MRAID_DMA_WSG:
                if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
-                       pci_dma_sync_sg(adapter->pdev,
+                       pci_dma_sync_sg_for_cpu(adapter->pdev,
                                        scb->scp->request_buffer,
                                        scb->scp->use_sg, PCI_DMA_FROMDEVICE);
                }
@@ -3591,7 +3597,7 @@ megaraid_cmm_register(adapter_t *adapter)
        adp.drvr_data           = (unsigned long)adapter;
        adp.pdev                = adapter->pdev;
        adp.issue_uioc          = megaraid_mbox_mm_handler;
-       adp.timeout             = 30;
+       adp.timeout             = 300;
        adp.max_kioc            = MBOX_MAX_USER_CMDS;
 
        if ((rval = mraid_mm_register_adp(&adp)) != 0) {
index 2f195ab..5828024 100644 (file)
@@ -21,8 +21,8 @@
 #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 MEGARAID_VERSION       "2.20.4.1"
+#define MEGARAID_EXT_VERSION   "(Release Date: Thu Nov  4 17:44:59 EST 2004)"
 
 
 /*
@@ -231,7 +231,7 @@ typedef struct {
        dma_addr_t                      mbox_dma;
        spinlock_t                      mailbox_lock;
        unsigned long                   baseport;
-       unsigned long                   baseaddr;
+       void __iomem *                  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];
index 8a6bc93..301ebef 100644 (file)
@@ -10,7 +10,7 @@
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_mm.c
- * Version     : v2.20.2.0 (August 19 2004)
+ * Version     : v2.20.2.3 (Dec 09 2004)
  *
  * Common management module
  */
@@ -60,7 +60,7 @@ EXPORT_SYMBOL(mraid_mm_register_adp);
 EXPORT_SYMBOL(mraid_mm_unregister_adp);
 
 static int majorno;
-static uint32_t drvr_ver       = 0x02200100;
+static uint32_t drvr_ver       = 0x02200201;
 
 static int adapters_count_g;
 static struct list_head adapters_list_g;
@@ -155,6 +155,17 @@ mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
                return rval;
        }
 
+       /*
+        * Check if adapter can accept ioctl. We may have marked it offline
+        * if any previous kioc had timedout on this controller.
+        */
+       if (!adp->quiescent) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid cmm: controller cannot accept cmds due to "
+                       "earlier errors\n" ));
+               return -EFAULT;
+       }
+
        /*
         * The following call will block till a kioc is available
         */
@@ -171,10 +182,15 @@ mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
        kioc->done = ioctl_done;
 
        /*
-        * Issue the IOCTL to the low level driver
+        * Issue the IOCTL to the low level driver. After the IOCTL completes
+        * release the kioc if and only if it was _not_ timedout. If it was
+        * timedout, that means that resources are still with low level driver.
         */
        if ((rval = lld_ioctl(adp, kioc))) {
-               mraid_mm_dealloc_kioc(adp, kioc);
+
+               if (!kioc->timedout)
+                       mraid_mm_dealloc_kioc(adp, kioc);
+
                return rval;
        }
 
@@ -581,6 +597,7 @@ mraid_mm_alloc_kioc(mraid_mmadp_t *adp)
        kioc->user_data         = NULL;
        kioc->user_data_len     = 0;
        kioc->user_pthru        = NULL;
+       kioc->timedout          = 0;
 
        return kioc;
 }
@@ -597,23 +614,27 @@ 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);
+       if (kioc->pool_index != -1) {
+               pool = &adp->dma_pool_list[kioc->pool_index];
 
-       /*
-        * 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;
+               /* This routine may be called in non-isr context also */
+               spin_lock_irqsave(&pool->lock, flags);
 
-       spin_unlock_irqrestore(&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);
@@ -667,6 +688,14 @@ lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
                del_timer_sync(tp);
        }
 
+       /*
+        * If the command had timedout, we mark the controller offline
+        * before returning
+        */
+       if (kioc->timedout) {
+               adp->quiescent = 0;
+       }
+
        return kioc->status;
 }
 
@@ -679,6 +708,10 @@ lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
 static void
 ioctl_done(uioc_t *kioc)
 {
+       uint32_t        adapno;
+       int             iterator;
+       mraid_mmadp_t*  adapter;
+
        /*
         * When the kioc returns from driver, make sure it still doesn't
         * have ENODATA in status. Otherwise, driver will hang on wait_event
@@ -691,7 +724,32 @@ ioctl_done(uioc_t *kioc)
                kioc->status = -EINVAL;
        }
 
-       wake_up(&wait_q);
+       /*
+        * Check if this kioc was timedout before. If so, nobody is waiting
+        * on this kioc. We don't have to wake up anybody. Instead, we just
+        * have to free the kioc
+        */
+       if (kioc->timedout) {
+               iterator        = 0;
+               adapter         = NULL;
+               adapno          = kioc->adapno;
+
+               con_log(CL_ANN, ( KERN_WARNING "megaraid cmm: completed "
+                                       "ioctl that was timedout before\n"));
+
+               list_for_each_entry(adapter, &adapters_list_g, list) {
+                       if (iterator++ == adapno) break;
+               }
+
+               kioc->timedout = 0;
+
+               if (adapter) {
+                       mraid_mm_dealloc_kioc( adapter, kioc );
+               }
+       }
+       else {
+               wake_up(&wait_q);
+       }
 }
 
 
@@ -706,6 +764,7 @@ lld_timedout(unsigned long ptr)
        uioc_t *kioc    = (uioc_t *)ptr;
 
        kioc->status    = -ETIME;
+       kioc->timedout  = 1;
 
        con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n"));
 
@@ -850,6 +909,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
        adapter->issue_uioc     = lld_adp->issue_uioc;
        adapter->timeout        = lld_adp->timeout;
        adapter->max_kioc       = lld_adp->max_kioc;
+       adapter->quiescent      = 1;
 
        /*
         * Allocate single blocks of memory for all required kiocs,
@@ -1120,9 +1180,7 @@ mraid_mm_init(void)
 
        INIT_LIST_HEAD(&adapters_list_g);
 
-#ifdef CONFIG_COMPAT
        register_ioctl32_conversion(MEGAIOCCMD, mraid_mm_compat_ioctl);
-#endif
 
        return 0;
 }
index effc23a..28f1fb4 100644 (file)
 #include "megaraid_ioctl.h"
 
 
-#define LSI_COMMON_MOD_VERSION "2.20.2.0"
+#define LSI_COMMON_MOD_VERSION "2.20.2.3"
 #define LSI_COMMON_MOD_EXT_VERSION     \
-               "(Release Date: Thu Aug 19 09:58:33 EDT 2004)"
-
+               "(Release Date: Thu Dec  9 19:02:14 EST 2004)"
 
 #define LSI_DBGLVL                     dbglevel
 
index 1700d4e..85f3a74 100644 (file)
@@ -60,23 +60,23 @@ MODULE_AUTHOR("Paul Mackerras (paulus@samba.org)");
 MODULE_DESCRIPTION("PowerMac MESH SCSI driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(sync_rate, "i");
-MODULE_PARM_DESC(sync_rate, "Synchronous rate (0..10, 0=async)");
-MODULE_PARM(sync_targets, "i");
-MODULE_PARM_DESC(sync_targets, "Bitmask of targets allowed to set synchronous");
-MODULE_PARM(resel_targets, "i");
-MODULE_PARM_DESC(resel_targets, "Bitmask of targets allowed to set disconnect");
-MODULE_PARM(debug_targets, "i");
-MODULE_PARM_DESC(debug_targets, "Bitmask of debugged targets");
-MODULE_PARM(init_reset_delay, "i");
-MODULE_PARM_DESC(init_reset_delay, "Initial bus reset delay (0=no reset)");
-
 static int sync_rate = CONFIG_SCSI_MESH_SYNC_RATE;
 static int sync_targets = 0xff;
 static int resel_targets = 0xff;
 static int debug_targets = 0;  /* print debug for these targets */
 static int init_reset_delay = CONFIG_SCSI_MESH_RESET_DELAY_MS;
 
+module_param(sync_rate, int, 0);
+MODULE_PARM_DESC(sync_rate, "Synchronous rate (0..10, 0=async)");
+module_param(sync_targets, int, 0);
+MODULE_PARM_DESC(sync_targets, "Bitmask of targets allowed to set synchronous");
+module_param(resel_targets, int, 0);
+MODULE_PARM_DESC(resel_targets, "Bitmask of targets allowed to set disconnect");
+module_param(debug_targets, int, 0644);
+MODULE_PARM_DESC(debug_targets, "Bitmask of debugged targets");
+module_param(init_reset_delay, int, 0);
+MODULE_PARM_DESC(init_reset_delay, "Initial bus reset delay (0=no reset)");
+
 static int mesh_sync_period = 100;
 static int mesh_sync_offset = 0;
 static unsigned char use_active_neg = 0;  /* bit mask for SEQ_ACTIVE_NEG if used */
@@ -144,9 +144,9 @@ struct mesh_target {
 };
 
 struct mesh_state {
-       volatile struct mesh_regs *mesh;
+       volatile struct mesh_regs __iomem *mesh;
        int     meshintr;
-       volatile struct dbdma_regs *dma;
+       volatile struct dbdma_regs __iomem *dma;
        int     dmaintr;
        struct  Scsi_Host *host;
        struct  mesh_state *next;
@@ -304,8 +304,8 @@ static inline void dumpslog(struct mesh_state *ms)
 static void
 mesh_dump_regs(struct mesh_state *ms)
 {
-       volatile struct mesh_regs *mr = ms->mesh;
-       volatile struct dbdma_regs *md = ms->dma;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
+       volatile struct dbdma_regs __iomem *md = ms->dma;
        int t;
        struct mesh_target *tp;
 
@@ -338,7 +338,7 @@ mesh_dump_regs(struct mesh_state *ms)
 /*
  * Flush write buffers on the bus path to the mesh
  */
-static inline void mesh_flush_io(volatile struct mesh_regs *mr)
+static inline void mesh_flush_io(volatile struct mesh_regs __iomem *mr)
 {
        (void)in_8(&mr->mesh_id);
 }
@@ -359,8 +359,8 @@ static void mesh_completed(struct mesh_state *ms, struct scsi_cmnd *cmd)
  */
 static void mesh_init(struct mesh_state *ms)
 {
-       volatile struct mesh_regs *mr = ms->mesh;
-       volatile struct dbdma_regs *md = ms->dma;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
+       volatile struct dbdma_regs __iomem *md = ms->dma;
 
        mesh_flush_io(mr);
        udelay(100);
@@ -388,8 +388,7 @@ static void mesh_init(struct mesh_state *ms)
                mesh_flush_io(mr);
 
                /* Wait for bus to come back */
-               current->state = TASK_UNINTERRUPTIBLE;
-               schedule_timeout((init_reset_delay * HZ) / 1000);
+               msleep(init_reset_delay);
        }
        
        /* Reconfigure controller */
@@ -407,7 +406,7 @@ static void mesh_init(struct mesh_state *ms)
 
 static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
 {
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
        int t, id;
 
        id = cmd->device->id;
@@ -468,7 +467,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
                                dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
                                     MKWORD(mr->interrupt, mr->exception,
                                            mr->error, mr->fifo_count));
-                               mesh_interrupt(0, (void *)ms, 0);
+                               mesh_interrupt(0, (void *)ms, NULL);
                                if (ms->phase != arbitrating)
                                        return;
                        }
@@ -506,7 +505,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
                dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
                     MKWORD(mr->interrupt, mr->exception,
                            mr->error, mr->fifo_count));
-               mesh_interrupt(0, (void *)ms, 0);
+               mesh_interrupt(0, (void *)ms, NULL);
                if (ms->phase != arbitrating)
                        return;
                dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
@@ -596,8 +595,8 @@ static void mesh_done(struct mesh_state *ms, int start_next)
        struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
 
        cmd = ms->current_req;
-       ms->current_req = 0;
-       tp->current_req = 0;
+       ms->current_req = NULL;
+       tp->current_req = NULL;
        if (cmd) {
                cmd->result = (ms->stat << 16) + cmd->SCp.Status;
                if (ms->stat == DID_OK)
@@ -639,7 +638,7 @@ static inline void add_sdtr_msg(struct mesh_state *ms)
 static void set_sdtr(struct mesh_state *ms, int period, int offset)
 {
        struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
        int v, tr;
 
        tp->sdtr_state = sdtr_done;
@@ -680,8 +679,8 @@ static void set_sdtr(struct mesh_state *ms, int period, int offset)
 static void start_phase(struct mesh_state *ms)
 {
        int i, seq, nb;
-       volatile struct mesh_regs *mr = ms->mesh;
-       volatile struct dbdma_regs *md = ms->dma;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
+       volatile struct dbdma_regs __iomem *md = ms->dma;
        struct scsi_cmnd *cmd = ms->current_req;
        struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
 
@@ -824,7 +823,7 @@ static void start_phase(struct mesh_state *ms)
 
 static inline void get_msgin(struct mesh_state *ms)
 {
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
        int i, n;
 
        n = mr->fifo_count;
@@ -856,7 +855,7 @@ static inline int msgin_length(struct mesh_state *ms)
 
 static void reselected(struct mesh_state *ms)
 {
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
        struct scsi_cmnd *cmd;
        struct mesh_target *tp;
        int b, t, prev;
@@ -989,7 +988,7 @@ static void handle_reset(struct mesh_state *ms)
        int tgt;
        struct mesh_target *tp;
        struct scsi_cmnd *cmd;
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
 
        for (tgt = 0; tgt < 8; ++tgt) {
                tp = &ms->tgts[tgt];
@@ -1031,7 +1030,7 @@ static irqreturn_t do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptre
 static void handle_error(struct mesh_state *ms)
 {
        int err, exc, count;
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
 
        err = in_8(&mr->error);
        exc = in_8(&mr->exception);
@@ -1125,7 +1124,7 @@ static void handle_error(struct mesh_state *ms)
 static void handle_exception(struct mesh_state *ms)
 {
        int exc;
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
 
        exc = in_8(&mr->exception);
        out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE);
@@ -1232,8 +1231,8 @@ static void handle_msgin(struct mesh_state *ms)
                        } else if (code != cmd->device->lun + IDENTIFY_BASE) {
                                printk(KERN_WARNING "mesh: lun mismatch "
                                       "(%d != %d) on reselection from "
-                                      "target %d\n", i, cmd->device->lun,
-                                      ms->conn_tgt);
+                                      "target %d\n", code - IDENTIFY_BASE,
+                                      cmd->device->lun, ms->conn_tgt);
                        }
                        break;
                }
@@ -1325,8 +1324,8 @@ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd)
 
 static void halt_dma(struct mesh_state *ms)
 {
-       volatile struct dbdma_regs *md = ms->dma;
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct dbdma_regs __iomem *md = ms->dma;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
        struct scsi_cmnd *cmd = ms->current_req;
        int t, nb;
 
@@ -1374,7 +1373,7 @@ static void halt_dma(struct mesh_state *ms)
 
 static void phase_mismatch(struct mesh_state *ms)
 {
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
        int phase;
 
        dlog(ms, "phasemm ch/cl/seq/fc=%.8x",
@@ -1453,7 +1452,7 @@ static void phase_mismatch(struct mesh_state *ms)
 
 static void cmd_complete(struct mesh_state *ms)
 {
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
        struct scsi_cmnd *cmd = ms->current_req;
        struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
        int seq, n, t;
@@ -1619,7 +1618,7 @@ static void cmd_complete(struct mesh_state *ms)
                        mesh_done(ms, 1);
                        return;
                case disconnecting:
-                       ms->current_req = 0;
+                       ms->current_req = NULL;
                        ms->phase = idle;
                        mesh_start(ms);
                        return;
@@ -1666,7 +1665,7 @@ static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
        struct mesh_state *ms = (struct mesh_state *) dev_id;
-       volatile struct mesh_regs *mr = ms->mesh;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
        int intr;
 
 #if 0
@@ -1714,8 +1713,8 @@ static int mesh_abort(struct scsi_cmnd *cmd)
 static int mesh_host_reset(struct scsi_cmnd *cmd)
 {
        struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
-       volatile struct mesh_regs *mr = ms->mesh;
-       volatile struct dbdma_regs *md = ms->dma;
+       volatile struct mesh_regs __iomem *mr = ms->mesh;
+       volatile struct dbdma_regs __iomem *md = ms->dma;
 
        printk(KERN_DEBUG "mesh_host_reset\n");
 
@@ -1749,12 +1748,10 @@ static void set_mesh_power(struct mesh_state *ms, int state)
                return;
        if (state) {
                pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ/5);
+               msleep(200);
        } else {
                pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ/100);
+               msleep(10);
        }
 }                      
 
@@ -1765,15 +1762,14 @@ static int mesh_suspend(struct macio_dev *mdev, u32 state)
        struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
        unsigned long flags;
 
-       if (state == mdev->ofdev.dev.power_state || state < 2)
+       if (state == mdev->ofdev.dev.power.power_state || state < 2)
                return 0;
 
        scsi_block_requests(ms->host);
        spin_lock_irqsave(ms->host->host_lock, flags);
        while(ms->phase != idle) {
                spin_unlock_irqrestore(ms->host->host_lock, flags);
-               current->state = TASK_UNINTERRUPTIBLE;
-               schedule_timeout(HZ/100);
+               msleep(10);
                spin_lock_irqsave(ms->host->host_lock, flags);
        }
        ms->phase = sleeping;
@@ -1781,7 +1777,7 @@ static int mesh_suspend(struct macio_dev *mdev, u32 state)
        disable_irq(ms->meshintr);
        set_mesh_power(ms, 0);
 
-       mdev->ofdev.dev.power_state = state;
+       mdev->ofdev.dev.power.power_state = state;
 
        return 0;
 }
@@ -1791,7 +1787,7 @@ static int mesh_resume(struct macio_dev *mdev)
        struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
        unsigned long flags;
 
-       if (mdev->ofdev.dev.power_state == 0)
+       if (mdev->ofdev.dev.power.power_state == 0)
                return 0;
 
        set_mesh_power(ms, 1);
@@ -1802,7 +1798,7 @@ static int mesh_resume(struct macio_dev *mdev)
        enable_irq(ms->meshintr);
        scsi_unblock_requests(ms->host);
 
-       mdev->ofdev.dev.power_state = 0;
+       mdev->ofdev.dev.power.power_state = 0;
 
        return 0;
 }
@@ -1817,7 +1813,7 @@ static int mesh_resume(struct macio_dev *mdev)
 static int mesh_shutdown(struct macio_dev *mdev)
 {
        struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
-       volatile struct mesh_regs *mr;
+       volatile struct mesh_regs __iomem *mr;
        unsigned long flags;
 
                printk(KERN_INFO "resetting MESH scsi bus(es)\n");
@@ -1896,17 +1892,15 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_match *match)
        ms->mdev = mdev;
        ms->pdev = pdev;
        
-       ms->mesh = (volatile struct mesh_regs *)
-               ioremap(macio_resource_start(mdev, 0), 0x1000);
+       ms->mesh = ioremap(macio_resource_start(mdev, 0), 0x1000);
        if (ms->mesh == NULL) {
                printk(KERN_ERR "mesh: can't map registers\n");
                goto out_free;
        }               
-       ms->dma = (volatile struct dbdma_regs *)
-               ioremap(macio_resource_start(mdev, 1), 0x1000);
+       ms->dma = ioremap(macio_resource_start(mdev, 1), 0x1000);
        if (ms->dma == NULL) {
                printk(KERN_ERR "mesh: can't map registers\n");
-               iounmap((void *)ms->mesh);
+               iounmap(ms->mesh);
                goto out_free;
        }
 
@@ -1938,7 +1932,7 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_match *match)
                for (tgt = 0; tgt < 8; ++tgt) {
                ms->tgts[tgt].sdtr_state = do_sdtr;
                ms->tgts[tgt].sync_params = ASYNC_PARAMS;
-               ms->tgts[tgt].current_req = 0;
+               ms->tgts[tgt].current_req = NULL;
                }
 
        if ((cfp = (int *) get_property(mesh, "clock-frequency", NULL)))
@@ -1972,8 +1966,8 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_match *match)
        return 0;
 
 out_unmap:
-       iounmap((void *)ms->dma);
-       iounmap((void *)ms->mesh);
+       iounmap(ms->dma);
+       iounmap(ms->mesh);
 out_free:
        scsi_host_put(mesh_host);
 out_release:
@@ -1998,8 +1992,8 @@ static int mesh_remove(struct macio_dev *mdev)
        set_mesh_power(ms, 0);
 
        /* Unmap registers & dma controller */
-       iounmap((void *) ms->mesh);
-               iounmap((void *) ms->dma);
+       iounmap(ms->mesh);
+               iounmap(ms->dma);
 
        /* Free DMA commands memory */
        pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size,
index 7e8e7fb..84bbc59 100644 (file)
@@ -552,14 +552,14 @@ typedef struct {
   int long_timeout;            /* timeout for commands known to take long time*/
 
   /* Mode characteristics */
-  ST_mode modes[ST_NBR_MODES];
+  struct st_modedef modes[ST_NBR_MODES];
   int current_mode;
 
   /* Status variables */
   int partition;
   int new_partition;
   int nbr_partitions;    /* zero until partition support enabled */
-  ST_partstat ps[ST_NBR_PARTITIONS];
+  struct st_partstat ps[ST_NBR_PARTITIONS];
   unsigned char dirty;
   unsigned char ready;
   unsigned char write_prot;
index 4277db3..84d0634 100644 (file)
@@ -85,7 +85,7 @@ static int pc_debug = PCMCIA_DEBUG;
 module_param(pc_debug, int, 0);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"sym53c500_cs.c 0.9b 2004/05/10 (Bob Tracy)";
+"sym53c500_cs.c 0.9c 2004/10/27 (Bob Tracy)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -95,13 +95,12 @@ static char *version =
 /* Parameters that can be set with 'insmod' */
 
 /* Bit map of interrupts to choose from */
-static unsigned int irq_mask = 0xdeb8; /* 3, 6, 7, 9-12, 14, 15 */
+static unsigned int irq_mask = 0xdeb8; /* 3-5, 7, 9-12, 14, 15 */
 static int irq_list[4] = { -1 };
-static int num_irqs = 1;
 
 module_param(irq_mask, int, 0);
 MODULE_PARM_DESC(irq_mask, "IRQ mask bits (default: 0xdeb8)");
-module_param_array(irq_list, int, num_irqs, 0);
+module_param_array(irq_list, int, NULL, 0);
 MODULE_PARM_DESC(irq_list, "Comma-separated list of up to 4 IRQs to try (default: auto select).");
 
 /* ================================================================== */
@@ -830,7 +829,7 @@ next_entry:
        data = (struct sym53c500_data *)host->hostdata;
 
        if (irq_level > 0) {
-               if (request_irq(irq_level, SYM53C500_intr, 0, "SYM53C500", host)) {
+               if (request_irq(irq_level, SYM53C500_intr, SA_SHIRQ, "SYM53C500", host)) {
                        printk("SYM53C500: unable to allocate IRQ %d\n", irq_level);
                        goto err_free_scsi;
                }
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;
+
index 73074e6..9db6a20 100644 (file)
  */
 
 #ifdef UNIQUE_FW_NAME
-unsigned short fw12160i_version = 10*1024+4;
+static unsigned char fw12160i_version_str[] = {10,4,32};
 #else
-unsigned short risc_code_version = 10*1024+4;
-#endif
-
-#ifdef UNIQUE_FW_NAME
-unsigned char fw12160i_version_str[] = {10,4,32};
-#else
-unsigned char firmware_version[] = {10,4,32};
+static unsigned char firmware_version[] = {10,4,32};
 #endif
 
 #ifdef UNIQUE_FW_NAME
@@ -44,15 +38,15 @@ unsigned char firmware_version[] = {10,4,32};
 #endif
 
 #ifdef UNIQUE_FW_NAME
-unsigned short fw12160i_addr01 = 0x1000;
+static unsigned short fw12160i_addr01 = 0x1000;
 #else
-unsigned short risc_code_addr01 = 0x1000;
+static unsigned short risc_code_addr01 = 0x1000;
 #endif
 
 #ifdef UNIQUE_FW_NAME
-unsigned short fw12160i_code01[] = {
+static unsigned short fw12160i_code01[] = {
 #else
-unsigned short risc_code01[] = {
+static unsigned short risc_code01[] = {
 #endif
        0x0804, 0x1041, 0x0000, 0x35e6, 0x0000, 0x2043, 0x4f50, 0x5952,
        0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31,
@@ -1781,7 +1775,7 @@ unsigned short risc_code01[] = {
        0x681f, 0x000c, 0x70a0, 0x70a2, 0x0005, 0x7c12
 };
 #ifdef UNIQUE_FW_NAME
-unsigned short   fw12160i_length01 = 0x35e6;
+static unsigned short   fw12160i_length01 = 0x35e6;
 #else
-unsigned short   risc_code_length01 = 0x35e6;
+static unsigned short   risc_code_length01 = 0x35e6;
 #endif
index 7ad051d..2621e99 100644 (file)
  */
 
 #ifdef UNIQUE_FW_NAME
-unsigned short fw1280ei_version = 8*1024+15;
+static unsigned char fw1280ei_version_str[] = {8,15,0};
 #else
-unsigned short risc_code_version = 8*1024+15;
-#endif
-
-#ifdef UNIQUE_FW_NAME
-unsigned char fw1280ei_version_str[] = {8,15,0};
-#else
-unsigned char firmware_version[] = {8,15,0};
+static unsigned char firmware_version[] = {8,15,0};
 #endif
 
 #ifdef UNIQUE_FW_NAME
@@ -45,15 +39,15 @@ unsigned char firmware_version[] = {8,15,0};
 #endif
 
 #ifdef UNIQUE_FW_NAME
-unsigned short fw1280ei_addr01 = 0x1000;
+static unsigned short fw1280ei_addr01 = 0x1000;
 #else
-unsigned short risc_code_addr01 = 0x1000;
+static unsigned short risc_code_addr01 = 0x1000;
 #endif
 
 #ifdef UNIQUE_FW_NAME
-unsigned short fw1280ei_code01[] = {
+static unsigned short fw1280ei_code01[] = {
 #else
-unsigned short risc_code01[] = {
+static unsigned short risc_code01[] = {
 #endif
        0x0078, 0x1041, 0x0000, 0x3d3b, 0x0000, 0x2043, 0x4f50, 0x5952,
        0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31,
@@ -2017,7 +2011,7 @@ unsigned short risc_code01[] = {
        0x70a2, 0x007c, 0x205b
 };
 #ifdef UNIQUE_FW_NAME
-unsigned short   fw1280ei_length01 = 0x3d3b;
+static unsigned short   fw1280ei_length01 = 0x3d3b;
 #else
-unsigned short   risc_code_length01 = 0x3d3b;
+static unsigned short   risc_code_length01 = 0x3d3b;
 #endif
index 55c6c4b..b1d4510 100644 (file)
  *     Firmware Version 1.19.16 (10:36 Nov 02, 2000)
  */
 
-unsigned short risc_code_addr01 = 0x1000 ;
+static unsigned short risc_code_addr01 = 0x1000 ;
 
-unsigned short risc_code_length2100 = 0x9260;
-unsigned short risc_code2100[] = {
+static unsigned short risc_code_length2100 = 0x9260;
+static unsigned short risc_code2100[] = {
        0x0078, 0x102d, 0x0000, 0x9260, 0x0000, 0x0001, 0x0013, 0x0010,
        0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939,
        0x3920, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241,
@@ -4729,8 +4729,8 @@ unsigned short risc_code2100[] = {
  *     Firmware Version 2.01.27 (11:07 Dec 18, 2000)
  */
 
-unsigned short risc_code_length2200 = 0x9cbf;
-unsigned short risc_code2200[] = { 
+static unsigned short risc_code_length2200 = 0x9cbf;
+static unsigned short risc_code2200[] = { 
        0x0470, 0x0000, 0x0000, 0x9cbf, 0x0000, 0x0002, 0x0001, 0x001b,
        0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939,
        0x3920, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241,
index aef957b..a21105c 100644 (file)
@@ -44,7 +44,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME                       "sata_nv"
-#define DRV_VERSION                    "0.03"
+#define DRV_VERSION                    "0.5"
 
 #define NV_PORTS                       2
 #define NV_PIO_MASK                    0x1f
@@ -218,10 +218,18 @@ static struct ata_port_operations nv_ops = {
        .host_stop              = nv_host_stop,
 };
 
+/* FIXME: The hardware provides the necessary SATA PHY controls
+ * to support ATA_FLAG_SATA_RESET.  However, it is currently
+ * necessary to disable that flag, to solve misdetection problems.
+ * See http://bugme.osdl.org/show_bug.cgi?id=3352 for more info.
+ *
+ * This problem really needs to be investigated further.  But in the
+ * meantime, we avoid ATA_FLAG_SATA_RESET to get people working.
+ */
 static struct ata_port_info nv_port_info = {
        .sht            = &nv_sht,
        .host_flags     = ATA_FLAG_SATA |
-                         ATA_FLAG_SATA_RESET |
+                         /* ATA_FLAG_SATA_RESET | */
                          ATA_FLAG_SRST |
                          ATA_FLAG_NO_LEGACY,
        .pio_mask       = NV_PIO_MASK,
@@ -234,6 +242,7 @@ MODULE_AUTHOR("NVIDIA");
 MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
 
 irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
 {
@@ -311,7 +320,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        static int printed_version = 0;
        struct nv_host *host;
        struct ata_port_info *ppi;
-       struct ata_probe_ent *probe_ent = NULL;
+       struct ata_probe_ent *probe_ent;
        int rc;
 
        if (!printed_version++)
@@ -319,11 +328,11 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
        rc = pci_enable_device(pdev);
        if (rc)
-               return rc;
+               goto err_out;
 
        rc = pci_request_regions(pdev, DRV_NAME);
        if (rc)
-               goto err_out;
+               goto err_out_disable;
 
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
@@ -332,18 +341,16 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                goto err_out_regions;
 
+       rc = -ENOMEM;
+
        ppi = &nv_port_info;
        probe_ent = ata_pci_init_native_mode(pdev, &ppi);
-       if (!probe_ent) {
-               rc = -ENOMEM;
+       if (!probe_ent)
                goto err_out_regions;
-       }
 
        host = kmalloc(sizeof(struct nv_host), GFP_KERNEL);
-       if (!host) {
-               rc = -ENOMEM;
+       if (!host)
                goto err_out_free_ent;
-       }
 
        host->host_desc = &nv_device_tbl[ent->driver_data];
 
@@ -354,8 +361,10 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
                probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5),
                                pci_resource_len(pdev, 5));
-               if (probe_ent->mmio_base == NULL)
-                       goto err_out_iounmap;
+               if (probe_ent->mmio_base == NULL) {
+                       rc = -EIO;
+                       goto err_out_free_host;
+               }
 
                base = (unsigned long)probe_ent->mmio_base;
 
@@ -373,14 +382,14 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_master(pdev);
 
-       // Enable hotplug event interrupts.
-       if (host->host_desc->enable_hotplug)
-               host->host_desc->enable_hotplug(probe_ent);
-
        rc = ata_device_add(probe_ent);
        if (rc != NV_PORTS)
                goto err_out_iounmap;
 
+       // Enable hotplug event interrupts.
+       if (host->host_desc->enable_hotplug)
+               host->host_desc->enable_hotplug(probe_ent);
+
        kfree(probe_ent);
 
        return 0;
@@ -388,15 +397,15 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 err_out_iounmap:
        if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO)
                iounmap(probe_ent->mmio_base);
-
+err_out_free_host:
+       kfree(host);
 err_out_free_ent:
        kfree(probe_ent);
-
 err_out_regions:
        pci_release_regions(pdev);
-
-err_out:
+err_out_disable:
        pci_disable_device(pdev);
+err_out:
        return rc;
 }
 
@@ -454,12 +463,13 @@ static void nv_check_hotplug(struct ata_host_set *host_set)
 
 static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
 {
+       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
        u8 intr_mask;
        u8 regval;
 
-       pci_read_config_byte(probe_ent->pdev, NV_MCP_SATA_CFG_20, &regval);
+       pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
        regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
-       pci_write_config_byte(probe_ent->pdev, NV_MCP_SATA_CFG_20, regval);
+       pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
 
        writeb(NV_INT_STATUS_HOTPLUG, probe_ent->mmio_base + NV_INT_STATUS_CK804);
 
@@ -471,6 +481,7 @@ static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
 
 static void nv_disable_hotplug_ck804(struct ata_host_set *host_set)
 {
+       struct pci_dev *pdev = to_pci_dev(host_set->dev);
        u8 intr_mask;
        u8 regval;
 
@@ -480,9 +491,9 @@ static void nv_disable_hotplug_ck804(struct ata_host_set *host_set)
 
        writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_CK804);
 
-       pci_read_config_byte(host_set->pdev, NV_MCP_SATA_CFG_20, &regval);
+       pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
        regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
-       pci_write_config_byte(host_set->pdev, NV_MCP_SATA_CFG_20, regval);
+       pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
 }
 
 static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
index 8da7614..20a0125 100644 (file)
@@ -40,7 +40,7 @@
 #include "sata_promise.h"
 
 #define DRV_NAME       "sata_sx4"
-#define DRV_VERSION    "0.50"
+#define DRV_VERSION    "0.7"
 
 
 enum {
@@ -248,7 +248,7 @@ static void pdc20621_host_stop(struct ata_host_set *host_set)
 
 static int pdc_port_start(struct ata_port *ap)
 {
-       struct pci_dev *pdev = ap->host_set->pdev;
+       struct device *dev = ap->host_set->dev;
        struct pdc_port_priv *pp;
        int rc;
 
@@ -263,7 +263,7 @@ static int pdc_port_start(struct ata_port *ap)
        }
        memset(pp, 0, sizeof(*pp));
 
-       pp->pkt = pci_alloc_consistent(pdev, 128, &pp->pkt_dma);
+       pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
        if (!pp->pkt) {
                rc = -ENOMEM;
                goto err_out_kfree;
@@ -283,11 +283,11 @@ err_out:
 
 static void pdc_port_stop(struct ata_port *ap)
 {
-       struct pci_dev *pdev = ap->host_set->pdev;
+       struct device *dev = ap->host_set->dev;
        struct pdc_port_priv *pp = ap->private_data;
 
        ap->private_data = NULL;
-       pci_free_consistent(pdev, 128, pp->pkt, pp->pkt_dma);
+       dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
        kfree(pp);
        ata_port_stop(ap);
 }
@@ -1190,8 +1190,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
                        error = 0;
                        break;     
                }
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout((i * 100) * HZ / 1000 + 1);
+               msleep(i*100);
        }
        return error;
 }
@@ -1224,8 +1223,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
        readl(mmio + PDC_TIME_CONTROL);
 
        /* Wait 3 seconds */
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(3 * HZ);
+       msleep(3000);
 
        /* 
           When timer is enabled, counter is decreased every internal
@@ -1399,7 +1397,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
        }
 
        memset(probe_ent, 0, sizeof(*probe_ent));
-       probe_ent->pdev = pdev;
+       probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
        mmio_base = ioremap(pci_resource_start(pdev, 3),
@@ -1494,6 +1492,7 @@ MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Promise SATA low-level driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
 
 module_init(pdc_sata_init);
 module_exit(pdc_sata_exit);
index 1becb36..c45b1ee 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_uli"
-#define DRV_VERSION    "0.11"
+#define DRV_VERSION    "0.2"
 
 enum {
        uli_5289                = 0,
@@ -150,18 +150,20 @@ static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg)
 
 static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
 {
+       struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
        unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg);
        u32 val;
 
-       pci_read_config_dword(ap->host_set->pdev, cfg_addr, &val);
+       pci_read_config_dword(pdev, cfg_addr, &val);
        return val;
 }
 
 static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
 {
+       struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
        unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr);
 
-       pci_write_config_dword(ap->host_set->pdev, cfg_addr, val);
+       pci_write_config_dword(pdev, cfg_addr, val);
 }
 
 static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
index fc81e41..6bc75a3 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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 SYM53C8XX_H
@@ -81,7 +68,6 @@
  */
 #if 1
 #define        SYM_LINUX_PROC_INFO_SUPPORT
-#define SYM_LINUX_BOOT_COMMAND_LINE_SUPPORT
 #define SYM_LINUX_USER_COMMAND_SUPPORT
 #define SYM_LINUX_USER_INFO_SUPPORT
 #define SYM_LINUX_DEBUG_CONTROL_SUPPORT
@@ -142,9 +128,7 @@ struct sym_driver_setup {
        u_char  scsi_bus_check;
        u_char  host_id;
 
-       u_char  reverse_probe;
        u_char  verbose;
-       u_short debug;
        u_char  settle_delay;
        u_char  use_nvram;
        u_long  excludes[8];
@@ -158,6 +142,7 @@ struct sym_driver_setup {
 #define SYM_SETUP_IRQ_MODE             sym_driver_setup.irq_mode
 #define SYM_SETUP_SCSI_BUS_CHECK       sym_driver_setup.scsi_bus_check
 #define SYM_SETUP_HOST_ID              sym_driver_setup.host_id
+#define boot_verbose                   sym_driver_setup.verbose
 
 /* Always enable parity. */
 #define SYM_SETUP_PCI_PARITY           1
@@ -176,54 +161,13 @@ struct sym_driver_setup {
        .irq_mode       = 0,                                    \
        .scsi_bus_check = 1,                                    \
        .host_id        = 7,                                    \
-       .reverse_probe  = 0,                                    \
        .verbose        = 0,                                    \
-       .debug          = 0,                                    \
        .settle_delay   = 3,                                    \
        .use_nvram      = 1,                                    \
 }
 
-/*
- *  Boot fail safe setup.
- *
- *  Override initial setup from boot command line:
- *    sym53c8xx=safe:y
- */
-#define SYM_LINUX_DRIVER_SAFE_SETUP {                          \
-       .max_tag        = 0,                                    \
-       .burst_order    = 0,                                    \
-       .scsi_led       = 0,                                    \
-       .scsi_diff      = 1,                                    \
-       .irq_mode       = 0,                                    \
-       .scsi_bus_check = 2,                                    \
-       .host_id        = 7,                                    \
-       .reverse_probe  = 0,                                    \
-       .verbose        = 2,                                    \
-       .debug          = 0,                                    \
-       .settle_delay   = 10,                                   \
-       .use_nvram      = 1,                                    \
-}
-
-/*
- *  This structure is initialized from linux config options.
- *  It can be overridden at boot-up by the boot command line.
- */
-#ifdef SYM_GLUE_C
-struct sym_driver_setup
-       sym_driver_setup = SYM_LINUX_DRIVER_SETUP;
-#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT
-u_int  sym_debug_flags = 0;
-#endif
-#else
 extern struct sym_driver_setup sym_driver_setup;
-#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT
-extern u_int sym_debug_flags;
-#endif
-#endif /* SYM_GLUE_C */
-
-#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT
+extern unsigned int sym_debug_flags;
 #define DEBUG_FLAGS    sym_debug_flags
-#endif
-#define boot_verbose   sym_driver_setup.verbose
 
 #endif /* SYM53C8XX_H */
index e547908..b0f58e7 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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 SYM_CONF_H
index 09f861a..2e1d89f 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. 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 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 AUTHORS 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.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 SYM_DEFS_H
 #define SYM_DEFS_H
 
-#define SYM_VERSION "2.1.18j"
+#define SYM_VERSION "2.1.18m"
 #define SYM_DRIVER_NAME        "sym-" SYM_VERSION
 
-/*
- *  Vendor.
- */
-#define PCI_VENDOR_NCR         0x1000
-
 /*
  *  PCI device identifier of SYMBIOS chips.
  */
-#define PCI_ID_SYM53C810       1
-#define PCI_ID_SYM53C810AP     5
-#define PCI_ID_SYM53C815       4
-#define PCI_ID_SYM53C820       2
-#define PCI_ID_SYM53C825       3
-#define PCI_ID_SYM53C860       6
-#define PCI_ID_SYM53C875       0xf
-#define PCI_ID_SYM53C875_2     0x8f
-#define PCI_ID_SYM53C885       0xd
-#define PCI_ID_SYM53C895       0xc
-#define PCI_ID_SYM53C896       0xb
-#define PCI_ID_SYM53C895A      0x12
-#define PCI_ID_SYM53C875A      0x13
-#define PCI_ID_LSI53C1010_33   0x20
-#define PCI_ID_LSI53C1010_66   0x21
-#define PCI_ID_LSI53C1510D     0xa
+#define PCI_ID_SYM53C810       PCI_DEVICE_ID_NCR_53C810
+#define PCI_ID_SYM53C810AP     PCI_DEVICE_ID_LSI_53C810AP
+#define PCI_ID_SYM53C815       PCI_DEVICE_ID_NCR_53C815
+#define PCI_ID_SYM53C820       PCI_DEVICE_ID_NCR_53C820
+#define PCI_ID_SYM53C825       PCI_DEVICE_ID_NCR_53C825
+#define PCI_ID_SYM53C860       PCI_DEVICE_ID_NCR_53C860
+#define PCI_ID_SYM53C875       PCI_DEVICE_ID_NCR_53C875
+#define PCI_ID_SYM53C875_2     PCI_DEVICE_ID_NCR_53C875J
+#define PCI_ID_SYM53C885       PCI_DEVICE_ID_NCR_53C885
+#define PCI_ID_SYM53C895       PCI_DEVICE_ID_NCR_53C895
+#define PCI_ID_SYM53C896       PCI_DEVICE_ID_NCR_53C896
+#define PCI_ID_SYM53C895A      PCI_DEVICE_ID_LSI_53C895A
+#define PCI_ID_SYM53C875A      PCI_DEVICE_ID_LSI_53C875A
+#define PCI_ID_LSI53C1010_33   PCI_DEVICE_ID_LSI_53C1010_33
+#define PCI_ID_LSI53C1010_66   PCI_DEVICE_ID_LSI_53C1010_66
+#define PCI_ID_LSI53C1510D     PCI_DEVICE_ID_LSI_53C1510
 
 /*
  *     SYM53C8XX device features descriptor.
@@ -776,33 +758,32 @@ struct sym_tblsel {
  *     Messages
  */
 
-#define        M_COMPLETE      (0x00)
-#define        M_EXTENDED      (0x01)
-#define        M_SAVE_DP       (0x02)
-#define        M_RESTORE_DP    (0x03)
-#define        M_DISCONNECT    (0x04)
-#define        M_ID_ERROR      (0x05)
-#define        M_ABORT         (0x06)
-#define        M_REJECT        (0x07)
-#define        M_NOOP          (0x08)
-#define        M_PARITY        (0x09)
-#define        M_LCOMPLETE     (0x0a)
-#define        M_FCOMPLETE     (0x0b)
-#define        M_RESET         (0x0c)
+#define        M_COMPLETE      COMMAND_COMPLETE
+#define        M_EXTENDED      EXTENDED_MESSAGE
+#define        M_SAVE_DP       SAVE_POINTERS
+#define        M_RESTORE_DP    RESTORE_POINTERS
+#define        M_DISCONNECT    DISCONNECT
+#define        M_ID_ERROR      INITIATOR_ERROR
+#define        M_ABORT         ABORT
+#define        M_REJECT        MESSAGE_REJECT
+#define        M_NOOP          NOP
+#define        M_PARITY        MSG_PARITY_ERROR
+#define        M_LCOMPLETE     LINKED_CMD_COMPLETE
+#define        M_FCOMPLETE     LINKED_FLG_CMD_COMPLETE
+#define        M_RESET         BUS_DEVICE_RESET
 #define        M_ABORT_TAG     (0x0d)
 #define        M_CLEAR_QUEUE   (0x0e)
-#define        M_INIT_REC      (0x0f)
-#define        M_REL_REC       (0x10)
+#define        M_INIT_REC      INITIATE_RECOVERY
+#define        M_REL_REC       RELEASE_RECOVERY
 #define        M_TERMINATE     (0x11)
-#define        M_SIMPLE_TAG    (0x20)
-#define        M_HEAD_TAG      (0x21)
-#define        M_ORDERED_TAG   (0x22)
+#define        M_SIMPLE_TAG    SIMPLE_QUEUE_TAG
+#define        M_HEAD_TAG      HEAD_OF_QUEUE_TAG
+#define        M_ORDERED_TAG   ORDERED_QUEUE_TAG
 #define        M_IGN_RESIDUE   (0x23)
-#define        M_IDENTIFY      (0x80)
 
-#define        M_X_MODIFY_DP   (0x00)
-#define        M_X_SYNC_REQ    (0x01)
-#define        M_X_WIDE_REQ    (0x03)
+#define        M_X_MODIFY_DP   EXTENDED_MODIFY_DATA_POINTER
+#define        M_X_SYNC_REQ    EXTENDED_SDTR
+#define        M_X_WIDE_REQ    EXTENDED_WDTR
 #define        M_X_PPR_REQ     (0x04)
 
 /*
@@ -817,15 +798,15 @@ struct sym_tblsel {
  *     Status
  */
 
-#define        S_GOOD          (0x00)
-#define        S_CHECK_COND    (0x02)
-#define        S_COND_MET      (0x04)
-#define        S_BUSY          (0x08)
-#define        S_INT           (0x10)
-#define        S_INT_COND_MET  (0x14)
-#define        S_CONFLICT      (0x18)
-#define        S_TERMINATED    (0x20)
-#define        S_QUEUE_FULL    (0x28)
+#define        S_GOOD          SAM_STAT_GOOD
+#define        S_CHECK_COND    SAM_STAT_CHECK_CONDITION
+#define        S_COND_MET      SAM_STAT_CONDITION_MET
+#define        S_BUSY          SAM_STAT_BUSY
+#define        S_INT           SAM_STAT_INTERMEDIATE
+#define        S_INT_COND_MET  SAM_STAT_INTERMEDIATE_CONDITION_MET
+#define        S_CONFLICT      SAM_STAT_RESERVATION_CONFLICT
+#define        S_TERMINATED    SAM_STAT_COMMAND_TERMINATED
+#define        S_QUEUE_FULL    SAM_STAT_TASK_SET_FULL
 #define        S_ILLEGAL       (0xff)
 
 #endif /* defined SYM_DEFS_H */
index 0c9eb07..c30d5cd 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #ifdef __FreeBSD__
@@ -411,7 +398,6 @@ void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
                if (opcode == 0) {
                        printf ("%s: ERROR0 IN SCRIPT at %d.\n",
                                sym_name(np), (int) (cur-start));
-                       MDELAY (10000);
                        ++cur;
                        continue;
                };
@@ -455,7 +441,6 @@ void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
                        if ((tmp1 ^ tmp2) & 3) {
                                printf ("%s: ERROR1 IN SCRIPT at %d.\n",
                                        sym_name(np), (int) (cur-start));
-                               MDELAY (10000);
                        }
                        /*
                         *  If PREFETCH feature not enabled, remove 
index 59333f4..43f6810 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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        SYM_FW_H
index afb3309..cdd92d8 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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
  */
 
 /*
index 025f266..7ea7151 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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
  */
 
 /*
index 5dd15fc..df1b9af 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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 SYM_GLUE_H
@@ -89,7 +76,6 @@
 
 #define SYM_OPT_HANDLE_DIR_UNKNOWN
 #define SYM_OPT_HANDLE_DEVICE_QUEUEING
-#define SYM_OPT_NVRAM_PRE_READ
 #define SYM_OPT_LIMIT_COMMAND_REORDERING
 #define        SYM_OPT_ANNOUNCE_TRANSFER_RATE
 
 #define        printf(args...)         printk(args)
 
 /*
- *  Insert a delay in micro-seconds and milli-seconds.
+ *  Insert a delay in micro-seconds
  */
 #define sym_udelay(us) udelay(us)
-#define sym_mdelay(ms) mdelay(ms)
 
 /*
  *  A 'read barrier' flushes any data that have been prefetched 
@@ -396,9 +381,6 @@ struct sym_shcb {
        u_short         io_ws;          /* IO window size               */
        int             irq;            /* IRQ number                   */
 
-       SYM_QUEHEAD     wait_cmdq;      /* Awaiting SCSI commands       */
-       SYM_QUEHEAD     busy_cmdq;      /* Enqueued SCSI commands       */
-
        struct timer_list timer;        /* Timer handler link header    */
        u_long          lasttime;
        u_long          settle_time;    /* Resetting the SCSI BUS       */
index dddf88b..383f48b 100644 (file)
@@ -3,6 +3,7 @@
  * of PCI-SCSI IO processors.
  *
  * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ * Copyright (c) 2003-2004  Matthew Wilcox <matthew@wil.cx>
  *
  * This driver is derived from the Linux sym53c8xx driver.
  * Copyright (C) 1998-2000  Gerard Roudier
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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 "sym_glue.h"
 #include "sym_nvram.h"
@@ -299,7 +287,6 @@ int sym_reset_scsi_bus(hcb_p np, int enab_int)
        }
 out:
        OUTB (nc_scntl1, 0);
-       /* MDELAY(100); */
        return retv;
 }
 
@@ -1516,6 +1503,7 @@ static void sym_check_goals(struct scsi_device *sdev)
                if (st->period > np->maxsync_dt)
                        st->period = np->maxsync_dt;
        } else {
+               st->options &= ~PPR_OPT_MASK;
                if (st->offset > np->maxoffs)
                        st->offset = np->maxoffs;
                if (st->period < np->minsync)
@@ -1523,7 +1511,7 @@ static void sym_check_goals(struct scsi_device *sdev)
                if (st->period > np->maxsync)
                        st->period = np->maxsync;
        }
-}              
+}
 
 /*
  *  Prepare the next negotiation message if needed.
@@ -1588,7 +1576,7 @@ static int sym_prepare_nego(hcb_p np, ccb_p cp, int nego, u_char *msgptr)
                msgptr[msglen++] = 0;
                msgptr[msglen++] = tp->tinfo.goal.offset;
                msgptr[msglen++] = tp->tinfo.goal.width;
-               msgptr[msglen++] = tp->tinfo.goal.options & PPR_OPT_DT;
+               msgptr[msglen++] = tp->tinfo.goal.options & PPR_OPT_MASK;
                break;
        };
 
@@ -1955,7 +1943,7 @@ void sym_start_up (hcb_p np, int reason)
        if (np->features & (FE_ULTRA2|FE_ULTRA3)) {
                OUTONW (nc_sien, SBMC);
                if (reason == 0) {
-                       MDELAY(100);
+                       mdelay(100);
                        INW (nc_sist);
                }
                np->scsi_mode = INB (nc_stest4) & SMODE;
@@ -2022,7 +2010,7 @@ void sym_start_up (hcb_p np, int reason)
 /*
  *  Switch trans mode for current job and it's target.
  */
-static void sym_settrans(hcb_p np, int target, u_char dt, u_char ofs,
+static void sym_settrans(hcb_p np, int target, u_char opts, u_char ofs,
                         u_char per, u_char wide, u_char div, u_char fak)
 {
        SYM_QUEHEAD *qp;
@@ -2073,7 +2061,7 @@ static void sym_settrans(hcb_p np, int target, u_char dt, u_char ofs,
         */
        if (np->features & FE_C10) {
                uval = uval & ~(U3EN|AIPCKEN);
-               if (dt) {
+               if (opts)       {
                        assert(np->features & FE_U3EN);
                        uval |= U3EN;
                }
@@ -2176,17 +2164,17 @@ sym_setsync(hcb_p np, int target,
  *  Let everything be aware of the changes.
  */
 static void 
-sym_setpprot(hcb_p np, int target, u_char dt, u_char ofs,
+sym_setpprot(hcb_p np, int target, u_char opts, u_char ofs,
              u_char per, u_char wide, u_char div, u_char fak)
 {
        tcb_p tp = &np->target[target];
 
-       sym_settrans(np, target, dt, ofs, per, wide, div, fak);
+       sym_settrans(np, target, opts, ofs, per, wide, div, fak);
 
        tp->tinfo.goal.width    = tp->tinfo.curr.width  = wide;
        tp->tinfo.goal.period   = tp->tinfo.curr.period = per;
        tp->tinfo.goal.offset   = tp->tinfo.curr.offset = ofs;
-       tp->tinfo.goal.options  = tp->tinfo.curr.options = dt;
+       tp->tinfo.goal.options  = tp->tinfo.curr.options = opts;
 
        sym_xpt_async_nego_ppr(np, target);
 }
@@ -2747,7 +2735,7 @@ unexpected_phase:
                if      (dsp == SCRIPTA_BA (np, send_ident)) {
                        if (cp->tag != NO_TAG && olen - rest <= 3) {
                                cp->host_status = HS_BUSY;
-                               np->msgout[0] = M_IDENTIFY | cp->lun;
+                               np->msgout[0] = IDENTIFY(0, cp->lun);
                                nxtdsp = SCRIPTB_BA (np, ident_break_atn);
                        }
                        else
@@ -3176,10 +3164,7 @@ static void sym_sir_bad_scsi_status(hcb_p np, int num, ccb_p cp)
                 *  requesting sense data.
                 */
 
-               /*
-                *  identify message
-                */
-               cp->scsi_smsg2[0] = M_IDENTIFY | cp->lun;
+               cp->scsi_smsg2[0] = IDENTIFY(0, cp->lun);
                msglen = 1;
 
                /*
@@ -3538,8 +3523,8 @@ static void sym_sir_task_recovery(hcb_p np, int num)
                 */
                if (lun != -1) {
                        lcb_p lp = sym_lp(np, tp, lun);
-                       lp->to_clear = 0; /* We donnot expect to fail here */
-                       np->abrt_msg[0] = M_IDENTIFY | lun;
+                       lp->to_clear = 0; /* We don't expect to fail here */
+                       np->abrt_msg[0] = IDENTIFY(0, lun);
                        np->abrt_msg[1] = M_ABORT;
                        np->abrt_tbl.size = 2;
                        break;
@@ -3580,7 +3565,7 @@ static void sym_sir_task_recovery(hcb_p np, int num)
                 *  We have some task to abort.
                 *  Set the IDENTIFY(lun)
                 */
-               np->abrt_msg[0] = M_IDENTIFY | cp->lun;
+               np->abrt_msg[0] = IDENTIFY(0, cp->lun);
 
                /*
                 *  If we want to abort an untagged command, we 
@@ -3591,8 +3576,7 @@ static void sym_sir_task_recovery(hcb_p np, int num)
                if (cp->tag == NO_TAG) {
                        np->abrt_msg[1] = M_ABORT;
                        np->abrt_tbl.size = 2;
-               }
-               else {
+               } else {
                        np->abrt_msg[1] = cp->scsi_smsg[1];
                        np->abrt_msg[2] = cp->scsi_smsg[2];
                        np->abrt_msg[3] = M_ABORT_TAG;
@@ -4152,20 +4136,17 @@ static int
 sym_ppr_nego_check(hcb_p np, int req, int target)
 {
        tcb_p tp = &np->target[target];
-       u_char  chg, ofs, per, fak, dt, div, wide;
+       unsigned char fak, div;
+       int dt, chg = 0;
+
+       unsigned char per = np->msgin[3];
+       unsigned char ofs = np->msgin[5];
+       unsigned char wide = np->msgin[6];
+       unsigned char opts = np->msgin[7] & PPR_OPT_MASK;
 
        if (DEBUG_FLAGS & DEBUG_NEGO) {
                sym_print_nego_msg(np, target, "ppr msgin", np->msgin);
-       };
-
-       /*
-        *  Get requested values.
-        */
-       chg  = 0;
-       per  = np->msgin[3];
-       ofs  = np->msgin[5];
-       wide = np->msgin[6];
-       dt   = np->msgin[7] & PPR_OPT_DT;
+       }
 
        /*
         *  Check values against our limits.
@@ -4175,29 +4156,30 @@ sym_ppr_nego_check(hcb_p np, int req, int target)
                wide = np->maxwide;
        }
        if (!wide || !(np->features & FE_ULTRA3))
-               dt &= ~PPR_OPT_DT;
+               opts = 0;
 
        if (!(np->features & FE_U3EN))  /* Broken U3EN bit not supported */
-               dt &= ~PPR_OPT_DT;
+               opts = 0;
 
-       if (dt != (np->msgin[7] & PPR_OPT_MASK)) chg = 1;
+       if (opts != (np->msgin[7] & PPR_OPT_MASK))
+               chg = 1;
+
+       dt = opts & PPR_OPT_DT;
 
        if (ofs) {
-               if (dt) {
-                       if (ofs > np->maxoffs_dt)
-                               {chg = 1; ofs = np->maxoffs_dt;}
+               unsigned char maxoffs = dt ? np->maxoffs_dt : np->maxoffs;
+               if (ofs > maxoffs) {
+                       chg = 1;
+                       ofs = maxoffs;
                }
-               else if (ofs > np->maxoffs)
-                       {chg = 1; ofs = np->maxoffs;}
        }
 
        if (ofs) {
-               if (dt) {
-                       if (per < np->minsync_dt)
-                               {chg = 1; per = np->minsync_dt;}
+               unsigned char minsync = dt ? np->minsync_dt : np->minsync;
+               if (per < np->minsync_dt) {
+                       chg = 1;
+                       per = minsync;
                }
-               else if (per < np->minsync)
-                       {chg = 1; per = np->minsync;}
        }
 
        /*
@@ -4217,7 +4199,7 @@ sym_ppr_nego_check(hcb_p np, int req, int target)
        /*
         *  Apply new values.
         */
-       sym_setpprot (np, target, dt, ofs, per, wide, div, fak);
+       sym_setpprot(np, target, opts, ofs, per, wide, div, fak);
 
        /*
         *  It was an answer. We are done.
@@ -4235,7 +4217,7 @@ sym_ppr_nego_check(hcb_p np, int req, int target)
        np->msgout[4] = 0;
        np->msgout[5] = ofs;
        np->msgout[6] = wide;
-       np->msgout[7] = dt;
+       np->msgout[7] = opts;
 
        if (DEBUG_FLAGS & DEBUG_NEGO) {
                sym_print_nego_msg(np, target, "ppr msgout", np->msgout);
@@ -4251,7 +4233,7 @@ reject_it:
         *  If it is a device response that should result in  
         *  ST, we may want to try a legacy negotiation later.
         */
-       if (!req && !dt) {
+       if (!req && !opts) {
                tp->tinfo.goal.options = 0;
                tp->tinfo.goal.width   = wide;
                tp->tinfo.goal.period  = per;
@@ -5284,8 +5266,9 @@ int sym_queue_scsiio(hcb_p np, cam_scsiio_p csio, ccb_p cp)
 {
        tcb_p   tp;
        lcb_p   lp;
-       u_char  idmsg, *msgptr;
+       u_char  *msgptr;
        u_int   msglen;
+       int can_disconnect;
 
        /*
         *  Keep track of the IO in our CCB.
@@ -5293,25 +5276,21 @@ int sym_queue_scsiio(hcb_p np, cam_scsiio_p csio, ccb_p cp)
        cp->cam_ccb = (cam_ccb_p) csio;
 
        /*
-        *  Retreive the target descriptor.
+        *  Retrieve the target descriptor.
         */
        tp = &np->target[cp->target];
 
        /*
-        *  Retreive the lun descriptor.
+        *  Retrieve the lun descriptor.
         */
        lp = sym_lp(np, tp, cp->lun);
 
-       /*
-        *  Build the IDENTIFY message.
-        */
-       idmsg = M_IDENTIFY | cp->lun;
-       if (cp->tag != NO_TAG || (lp && (lp->curr_flags & SYM_DISC_ENABLED)))
-               idmsg |= 0x40;
+       can_disconnect = (cp->tag != NO_TAG) ||
+               (lp && (lp->curr_flags & SYM_DISC_ENABLED));
 
        msgptr = cp->scsi_smsg;
        msglen = 0;
-       msgptr[msglen++] = idmsg;
+       msgptr[msglen++] = IDENTIFY(can_disconnect, cp->lun);
 
        /*
         *  Build the tag message if present.
@@ -5518,7 +5497,6 @@ void sym_complete_error (hcb_p np, ccb_p cp)
                printf ("CCB=%lx STAT=%x/%x/%x DEV=%d/%d\n", (unsigned long)cp,
                        cp->host_status, cp->ssss_status, cp->host_flags,
                        cp->target, cp->lun);
-               MDELAY(100);
        }
 
        /*
@@ -5746,15 +5724,8 @@ if (resid)
 /*
  *  Soft-attach the controller.
  */
-#ifdef SYM_OPT_NVRAM_PRE_READ
 int sym_hcb_attach(hcb_p np, struct sym_fw *fw, struct sym_nvram *nvram)
-#else
-int sym_hcb_attach(hcb_p np, struct sym_fw *fw)
-#endif
 {
-#ifndef SYM_OPT_NVRAM_PRE_READ
-       struct sym_nvram nvram_buf, *nvram = &nvram_buf;
-#endif
        int i;
 
        /*
@@ -5780,13 +5751,6 @@ int sym_hcb_attach(hcb_p np, struct sym_fw *fw)
         */
        sym_chip_reset (np);
 
-       /*
-        *  Try to read the user set-up.
-        */
-#ifndef SYM_OPT_NVRAM_PRE_READ
-       (void) sym_read_nvram(np, nvram);
-#endif
-
        /*
         *  Prepare controller and devices settings, according 
         *  to chip features, user set-up and driver set-up.
index 04b5411..4d3b989 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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 SYM_HIPD_H
@@ -1121,12 +1108,7 @@ int sym_abort_scsiio(hcb_p np, cam_ccb_p ccb, int timed_out);
 int sym_abort_ccb(hcb_p np, ccb_p cp, int timed_out);
 int sym_reset_scsi_target(hcb_p np, int target);
 void sym_hcb_free(hcb_p np);
-
-#ifdef SYM_OPT_NVRAM_PRE_READ
 int sym_hcb_attach(hcb_p np, struct sym_fw *fw, struct sym_nvram *nvram);
-#else
-int sym_hcb_attach(hcb_p np, struct sym_fw *fw);
-#endif
 
 /*
  *  Optionnaly, the driver may handle IO timeouts.
@@ -1350,7 +1332,6 @@ u32 __vtobus_unlocked(m_pool_ident_t dev_dmat, void *m);
 #define PRINT_ADDR     sym_print_addr
 #define PRINT_TARGET   sym_print_target
 #define PRINT_LUN      sym_print_lun
-#define MDELAY         sym_mdelay
 #define UDELAY         sym_udelay
 
 #endif /* SYM_HIPD_H */
index c0df21c..567a6dd 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #ifdef __FreeBSD__
index 6b3c8b8..f27f52e 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #ifdef __FreeBSD__
@@ -203,10 +190,12 @@ void sym_announce_transfer_rate(hcb_p np, int target)
                        mb10 = (f10 + period/2) / period;
                }
                printf_info (
-                   "%s:%d: %s %sSCSI %d.%d MB/s %s (%d.%d ns, offset %d)\n",
+                   "%s:%d: %s %sSCSI %d.%d MB/s %s%s%s (%d.%d ns, offset %d)\n",
                    sym_name(np), target, scsi, __tcurr.width? "WIDE " : "",
                    mb10/10, mb10%10,
                    (__tcurr.options & PPR_OPT_DT) ? "DT" : "ST",
+                   (__tcurr.options & PPR_OPT_IU) ? " IU" : "",
+                   (__tcurr.options & PPR_OPT_QAS) ? " QAS" : "",
                    period/10, period%10, __tcurr.offset);
        }
        else
index 4568f0c..0433d5d 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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 SYM_MISC_H
index ca857ff..f362132 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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 "sym_glue.h"
index ff3a8bf..a6bd02a 100644 (file)
  *
  *-----------------------------------------------------------------------------
  *
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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.
+ * 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 SYM_NVRAM_H
index 0f8286c..161ba53 100644 (file)
@@ -111,28 +111,28 @@ static int t128_device_reset(Scsi_Cmnd *);
 #ifndef HOSTS_C
 
 #define NCR5380_implementation_fields \
-    unsigned long base
+    void __iomem *base
 
 #define NCR5380_local_declare() \
-    unsigned long base
+    void __iomem *base
 
 #define NCR5380_setup(instance) \
-    base = (instance)->base
+    base = ((struct NCR5380_hostdata *)(instance->hostdata))->base
 
 #define T128_address(reg) (base + T_5380_OFFSET + ((reg) * 0x20))
 
 #if !(TDEBUG & TDEBUG_TRANSFER) 
-#define NCR5380_read(reg) isa_readb(T128_address(reg))
-#define NCR5380_write(reg, value) isa_writeb((value),(T128_address(reg)))
+#define NCR5380_read(reg) readb(T128_address(reg))
+#define NCR5380_write(reg, value) writeb((value),(T128_address(reg)))
 #else
 #define NCR5380_read(reg)                                              \
     (((unsigned char) printk("scsi%d : read register %d at address %08x\n"\
-    , instance->hostno, (reg), T128_address(reg))), isa_readb(T128_address(reg)))
+    , instance->hostno, (reg), T128_address(reg))), readb(T128_address(reg)))
 
 #define NCR5380_write(reg, value) {                                    \
     printk("scsi%d : write %02x to register %d at address %08x\n",     \
            instance->hostno, (value), (reg), T128_address(reg));       \
-    isa_writeb((value), (T128_address(reg)));                          \
+    writeb((value), (T128_address(reg)));                              \
 }
 #endif
 
index 511a40b..759addd 100644 (file)
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/console.h>
+#include <linux/device.h>
+#include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
-#include <linux/device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/mach-types.h>
 #include <asm/hardware/dec21285.h>
 #include <asm/hardware.h>
 
@@ -90,22 +92,21 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r
 {
        struct uart_port *port = dev_id;
        struct tty_struct *tty = port->info->tty;
-       unsigned int status, ch, rxs, max_count = 256;
+       unsigned int status, ch, flag, rxs, max_count = 256;
 
        status = *CSR_UARTFLG;
        while (!(status & 0x10) && max_count--) {
                if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                       tty->flip.work.func((void *)tty);
-                       if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                               printk(KERN_WARNING "TTY_DONT_FLIP set\n");
-                               goto out;
-                       }
+                       if (tty->low_latency)
+                               tty_flip_buffer_push(tty);
+                       /*
+                        * If this failed then we will throw away the
+                        * bytes but must do so to clear interrupts
+                        */
                }
 
                ch = *CSR_UARTDR;
-
-               *tty->flip.char_buf_ptr = ch;
-               *tty->flip.flag_buf_ptr = TTY_NORMAL;
+               flag = TTY_NORMAL;
                port->icount.rx++;
 
                rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
@@ -120,15 +121,13 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r
                        rxs &= port->read_status_mask;
 
                        if (rxs & RXSTAT_PARITY)
-                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                               flag = TTY_PARITY;
                        else if (rxs & RXSTAT_FRAME)
-                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               flag = TTY_FRAME;
                }
 
                if ((rxs & port->ignore_status_mask) == 0) {
-                       tty->flip.flag_buf_ptr++;
-                       tty->flip.char_buf_ptr++;
-                       tty->flip.count++;
+                       tty_insert_flip_char(tty, ch, flag);
                }
                if ((rxs & RXSTAT_OVERRUN) &&
                    tty->flip.count < TTY_FLIPBUF_SIZE) {
@@ -137,9 +136,7 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r
                         * immediately, and doesn't affect the current
                         * character.
                         */
-                       *tty->flip.char_buf_ptr++ = 0;
-                       *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
-                       tty->flip.count++;
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
                }
                status = *CSR_UARTFLG;
        }
index 6dd5224..36f2fb0 100644 (file)
 #include <linux/keyboard.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/segment.h>
-#include <asm/bitops.h>
 #include <asm/delay.h>
 #include <asm/uaccess.h>
 
@@ -757,7 +758,7 @@ static void rs_flush_chars(struct tty_struct *tty)
 
 extern void console_printn(const char * b, int count);
 
-static int rs_write(struct tty_struct * tty, int from_user,
+static int rs_write(struct tty_struct * tty,
                    const unsigned char *buf, int count)
 {
        int     c, total = 0;
@@ -779,15 +780,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
                if (c <= 0)
                        break;
 
-               if (from_user) {
-                       down(&tmp_buf_sem);
-                       copy_from_user(tmp_buf, buf, c);
-                       c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                      SERIAL_XMIT_SIZE - info->xmit_head));
-                       memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-                       up(&tmp_buf_sem);
-               } else
-                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
+               memcpy(info->xmit_buf + info->xmit_head, buf, c);
                info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
                info->xmit_cnt += c;
                restore_flags(flags);
@@ -1005,7 +998,7 @@ static void send_break(    struct m68k_serial * info, int duration)
         unsigned long flags;
         if (!info->port)
                 return;
-        current->state = TASK_INTERRUPTIBLE;
+        set_current_state(TASK_INTERRUPTIBLE);
         save_flags(flags);
         cli();
 #ifdef USE_INTS        
@@ -1197,8 +1190,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 #endif 
        if (info->blocked_open) {
                if (info->close_delay) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(info->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
                }
                wake_up_interruptible(&info->open_wait);
        }
index 79c0368..b4cb2fb 100644 (file)
@@ -17,7 +17,8 @@
 
 #include <linux/config.h>
 
-void serial8250_get_irq_map(unsigned int *map);
+int serial8250_register_port(struct uart_port *);
+void serial8250_unregister_port(int line);
 void serial8250_suspend_port(int line);
 void serial8250_resume_port(int line);
 
@@ -38,14 +39,16 @@ struct old_serial_port {
  */
 struct serial8250_config {
        const char      *name;
-       unsigned int    fifo_size;
-       unsigned int    tx_loadsz;
+       unsigned short  fifo_size;
+       unsigned short  tx_loadsz;
+       unsigned char   fcr;
        unsigned int    flags;
 };
 
 #define UART_CAP_FIFO  (1 << 8)        /* UART has FIFO */
 #define UART_CAP_EFR   (1 << 9)        /* UART has EFR */
 #define UART_CAP_SLEEP (1 << 10)       /* UART has IER sleep */
+#define UART_CAP_AFE   (1 << 11)       /* MCR-based hw flow control */
 
 #undef SERIAL_DEBUG_PCI
 
@@ -69,3 +72,14 @@ struct serial8250_config {
 #else
 #define SERIAL8250_SHARE_IRQS 0
 #endif
+
+#if defined(__alpha__) && !defined(CONFIG_PCI)
+/*
+ * Digital did something really horribly wrong with the OUT1 and OUT2
+ * lines on at least some ALPHA's.  The failure mode is that if either
+ * is cleared, the machine locks up with endless interrupts.
+ */
+#define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
+#else
+#define ALPHA_KLUDGE_MCR 0
+#endif
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);
index 97482be..a95bde8 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
-#include <linux/serial.h>
+#include <linux/serial_core.h>
 #include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <asm/hardware.h>
 #include <asm/parisc-device.h>
 #include <asm/io.h>
-#include <asm/serial.h>
+#include <asm/serial.h> /* for LASI_BASE_BAUD */
 
-static void setup_parisc_serial(struct serial_struct *serial,
-               unsigned long address, int irq, int line)
-{
-       memset(serial, 0, sizeof(struct serial_struct));
-
-       /* autoconfig() sets state->type.  This sets info->type */
-       serial->type = PORT_16550A;
-
-       serial->line = line;
-       serial->iomap_base = address;
-       serial->iomem_base = ioremap(address, 0x8);
-
-       serial->irq = irq;
-       serial->io_type = SERIAL_IO_MEM;        /* define access method */
-       serial->flags = 0;
-       serial->xmit_fifo_size = 16;
-       serial->custom_divisor = 0;
-       serial->baud_base = LASI_BASE_BAUD;
-}
+#include "8250.h"
 
 static int __init 
 serial_init_chip(struct parisc_device *dev)
 {
        static int serial_line_nr;
+       struct uart_port port;
        unsigned long address;
        int err;
 
-       struct serial_struct *serial;
-
        if (!dev->irq) {
                /* We find some unattached serial ports by walking native
                 * busses.  These should be silently ignored.  Otherwise,
@@ -66,21 +47,23 @@ serial_init_chip(struct parisc_device *dev)
                return -ENODEV;
        }
 
-       serial = kmalloc(sizeof(*serial), GFP_KERNEL);
-       if (!serial)
-               return -ENOMEM;
-
        address = dev->hpa;
        if (dev->id.sversion != 0x8d) {
                address += 0x800;
        }
 
-       setup_parisc_serial(serial, address, dev->irq, serial_line_nr++);
-       err = register_serial(serial);
+       memset(&port, 0, sizeof(struct uart_port));
+       port.mapbase = address;
+       port.irq = dev->irq;
+       port.iotype = UPIO_MEM;
+       port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+       port.uartclk = LASI_BASE_BAUD * 16;
+       port.dev = &dev->dev;
+
+       err = serial8250_register_port(&port);
        if (err < 0) {
-               printk(KERN_WARNING "register_serial returned error %d\n", err);
-               kfree(serial);
-               return -ENODEV;
+               printk(KERN_WARNING "serial8250_register_port returned error %d\n", err);
+               return err;
        }
 
        return 0;
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");
index b88c00b..ac57fdc 100644 (file)
  * and hooked into this driver.
  */
 #include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/serial.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/amba.h>
-
-#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
 #include <asm/hardware/amba_serial.h>
 
 #define UART_NR                2
@@ -149,22 +149,22 @@ pl010_rx_chars(struct uart_port *port)
 #endif
 {
        struct tty_struct *tty = port->info->tty;
-       unsigned int status, ch, rsr, max_count = 256;
+       unsigned int status, ch, flag, rsr, max_count = 256;
 
        status = UART_GET_FR(port);
        while (UART_RX_DATA(status) && max_count--) {
                if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                       tty->flip.work.func((void *)tty);
-                       if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                               printk(KERN_WARNING "TTY_DONT_FLIP set\n");
-                               return;
-                       }
+                       if (tty->low_latency)
+                               tty_flip_buffer_push(tty);
+                       /*
+                        * If this failed then we will throw away the
+                        * bytes but must do so to clear interrupts.
+                        */
                }
 
                ch = UART_GET_CHAR(port);
+               flag = TTY_NORMAL;
 
-               *tty->flip.char_buf_ptr = ch;
-               *tty->flip.flag_buf_ptr = TTY_NORMAL;
                port->icount.rx++;
 
                /*
@@ -188,20 +188,18 @@ pl010_rx_chars(struct uart_port *port)
                        rsr &= port->read_status_mask;
 
                        if (rsr & UART01x_RSR_BE)
-                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                               flag = TTY_BREAK;
                        else if (rsr & UART01x_RSR_PE)
-                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                               flag = TTY_PARITY;
                        else if (rsr & UART01x_RSR_FE)
-                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               flag = TTY_FRAME;
                }
 
                if (uart_handle_sysrq_char(port, ch, regs))
                        goto ignore_char;
 
                if ((rsr & port->ignore_status_mask) == 0) {
-                       tty->flip.flag_buf_ptr++;
-                       tty->flip.char_buf_ptr++;
-                       tty->flip.count++;
+                       tty_insert_flip_char(tty, ch, flag);
                }
                if ((rsr & UART01x_RSR_OE) &&
                    tty->flip.count < TTY_FLIPBUF_SIZE) {
@@ -210,9 +208,7 @@ pl010_rx_chars(struct uart_port *port)
                         * immediately, and doesn't affect the current
                         * character
                         */
-                       *tty->flip.char_buf_ptr++ = 0;
-                       *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
-                       tty->flip.count++;
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
                }
        ignore_char:
                status = UART_GET_FR(port);
@@ -714,6 +710,24 @@ static struct console amba_console = {
        .data           = &amba_reg,
 };
 
+static int __init amba_console_init(void)
+{
+       /*
+        * All port initializations are done statically
+        */
+       register_console(&amba_console);
+       return 0;
+}
+console_initcall(amba_console_init);
+
+static int __init amba_late_console_init(void)
+{
+       if (!(amba_console.flags & CON_ENABLED))
+               register_console(&amba_console);
+       return 0;
+}
+late_initcall(amba_late_console_init);
+
 #define AMBA_CONSOLE   &amba_console
 #else
 #define AMBA_CONSOLE   NULL
index 4aaef99..16592fa 100644 (file)
  *
  */
 #include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/serial.h>
 #include <linux/console.h>
 #include <linux/sysrq.h>
 #include <linux/spinlock.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/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-
-#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
 #include <asm/hardware/clps7111.h>
 
 #define UART_NR                2
@@ -123,9 +123,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re
                        goto ignore_char;
 
        error_return:
-               *tty->flip.flag_buf_ptr++ = flg;
-               *tty->flip.char_buf_ptr++ = ch;
-               tty->flip.count++;
+               tty_insert_flip_char(tty, ch, flg);
        ignore_char:
                status = clps_readl(SYSFLG(port));
        }
@@ -158,11 +156,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re
                 * CHECK: does overrun affect the current character?
                 * ASSUMPTION: it does not.
                 */
-               *tty->flip.flag_buf_ptr++ = flg;
-               *tty->flip.char_buf_ptr++ = ch;
-               tty->flip.count++;
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                       goto ignore_char;
+               tty_insert_flip_char(tty, ch, flg);
                ch = 0;
                flg = TTY_OVERRUN;
        }
index 598704e..5f6187b 100644 (file)
 #include "cpm_uart_cpm1.h"
 #endif
 
-#ifndef CONFIG_SERIAL_8250
-#define SERIAL_CPM_MAJOR       TTY_MAJOR
-#define SERIAL_CPM_MINOR       64
-#else
 #define SERIAL_CPM_MAJOR       204
-#define SERIAL_CPM_MINOR       42
-#endif
+#define SERIAL_CPM_MINOR       46
 
 #define IS_SMC(pinfo)          (pinfo->flags & FLAG_SMC)
 #define IS_DISCARDING(pinfo)   (pinfo->flags & FLAG_DISCARDING)
@@ -70,6 +65,8 @@ struct uart_cpm_port {
        /* helpers */
        int                      baud;
        int                      bits;
+       /* Keep track of 'odd' SMC2 wirings */
+       int                     is_portb;
 };
 
 extern int cpm_uart_port_map[UART_NR];
index 34f4c67..73306b9 100644 (file)
@@ -743,6 +743,18 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
        pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE;
        pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE;
 
+/*
+ *  In case SMC1 is being relocated...
+ */
+#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
+       up->smc_rbptr = pinfo->smcup->smc_rbase;
+       up->smc_tbptr = pinfo->smcup->smc_tbase;
+       up->smc_rstate = 0;
+       up->smc_tstate = 0;
+       up->smc_brkcr = 1;              /* number of break chars */
+       up->smc_brkec = 0;
+#endif
+
        /* Set up the uart parameters in the
         * parameter ram.
         */
@@ -872,6 +884,9 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
                .rx_nrfifos = RX_NUM_FIFO, 
                .rx_fifosize = RX_BUF_SIZE,
                .set_lineif = smc2_lineif,
+#ifdef CONFIG_SERIAL_CPM_ALT_SMC2
+               .is_portb = 1,
+#endif
        },
        [UART_SCC1] = {
                .port = {
index a9ab047..de26cf7 100644 (file)
@@ -82,10 +82,17 @@ void cpm_line_cr_cmd(int line, int cmd)
 void smc1_lineif(struct uart_cpm_port *pinfo)
 {
        volatile cpm8xx_t *cp = cpmp;
-
-       cp->cp_pbpar |= 0x000000c0;
-       cp->cp_pbdir &= ~0x000000c0;
-       cp->cp_pbodr &= ~0x000000c0;
+       unsigned int iobits = 0x000000c0;
+
+       if (!pinfo->is_portb) {
+               cp->cp_pbpar |= iobits;
+               cp->cp_pbdir &= ~iobits;
+               cp->cp_pbodr &= ~iobits;
+       } else {
+               ((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits;
+               ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits;
+               ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits;
+       }
 
        pinfo->brg = 1;
 }
@@ -194,8 +201,16 @@ int cpm_uart_init_portdesc(void)
        cpm_uart_nr = 0;
 #ifdef CONFIG_SERIAL_CPM_SMC1
        cpm_uart_ports[UART_SMC1].smcp = &cpmp->cp_smc[0];
+/*
+ *  Is SMC1 being relocated?
+ */
+# ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
+       cpm_uart_ports[UART_SMC1].smcup =
+           (smc_uart_t *) & cpmp->cp_dparam[0x3C0];
+# else
        cpm_uart_ports[UART_SMC1].smcup =
            (smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC1];
+# endif
        cpm_uart_ports[UART_SMC1].port.mapbase =
            (unsigned long)&cpmp->cp_smc[0];
        cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
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 */
index 293d172..97824ee 100644 (file)
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/console.h>
-#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/serial_core.h>
+#include <linux/serial.h>
 
 #include <asm/bootinfo.h>
 #include <asm/dec/interrupts.h>
@@ -186,7 +187,7 @@ static inline void dz_receive_chars(struct dz_port *dport)
        struct uart_icount *icount;
        int ignore = 0;
        unsigned short status, tmp;
-       unsigned char ch;
+       unsigned char ch, flag;
 
        /* this code is going to be a problem...
           the call to tty_flip_buffer is going to need
@@ -201,6 +202,7 @@ static inline void dz_receive_chars(struct dz_port *dport)
 
 
                ch = UCHAR(status);     /* grab the char */
+               flag = TTY_NORMAL;
 
 #if 0
                if (info->is_console) {
@@ -217,8 +219,6 @@ static inline void dz_receive_chars(struct dz_port *dport)
                if (tty->flip.count >= TTY_FLIPBUF_SIZE)
                        break;
 
-               *tty->flip.char_buf_ptr = ch;
-               *tty->flip.flag_buf_ptr = 0;
                icount->rx++;
 
                /* keep track of the statistics */
@@ -243,12 +243,12 @@ static inline void dz_receive_chars(struct dz_port *dport)
                        tmp = status & dport->port.read_status_mask;
 
                        if (tmp & DZ_PERR) {
-                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                               flag = TTY_PARITY;
 #ifdef DEBUG_DZ
                                debug_console("PERR\n", 5);
 #endif
                        } else if (tmp & DZ_FERR) {
-                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               flag = TTY_FRAME;
 #ifdef DEBUG_DZ
                                debug_console("FERR\n", 5);
 #endif
@@ -257,17 +257,12 @@ static inline void dz_receive_chars(struct dz_port *dport)
 #ifdef DEBUG_DZ
                                debug_console("OERR\n", 5);
 #endif
-                               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_insert_flip_char(tty, ch, flag);
+                               ch = 0;
+                               flag = TTY_OVERRUN;
                        }
                }
-               tty->flip.flag_buf_ptr++;
-               tty->flip.char_buf_ptr++;
-               tty->flip.count++;
+               tty_insert_flip_char(tty, ch, flag);
              ignore_char:
        } while (status & DZ_DVAL);
 
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 */
index 7f1b9ee..d8875ae 100644 (file)
 #include <linux/serialP.h>
 #include <linux/console.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/semaphore.h>
-#include <asm/bitops.h>
 #include <asm/delay.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -735,7 +736,7 @@ static void mcfrs_flush_chars(struct tty_struct *tty)
        local_irq_restore(flags);
 }
 
-static int mcfrs_write(struct tty_struct * tty, int from_user,
+static int mcfrs_write(struct tty_struct * tty,
                    const unsigned char *buf, int count)
 {
        volatile unsigned char  *uartp;
@@ -744,8 +745,8 @@ static int mcfrs_write(struct tty_struct * tty, int from_user,
        int                     c, total = 0;
 
 #if 0
-       printk("%s(%d): mcfrs_write(tty=%x,from_user=%d,buf=%x,count=%d)\n",
-               __FILE__, __LINE__, (int)tty, from_user, (int)buf, count);
+       printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n",
+               __FILE__, __LINE__, (int)tty, (int)buf, count);
 #endif
 
        if (serial_paranoia_check(info, tty->name, "mcfrs_write"))
@@ -764,19 +765,7 @@ static int mcfrs_write(struct tty_struct * tty, int from_user,
                if (c <= 0)
                        break;
 
-               if (from_user) {
-                       down(&mcfrs_tmp_buf_sem);
-                       if (copy_from_user(mcfrs_tmp_buf, buf, c))
-                               return -EFAULT;
-
-                       local_irq_disable();
-                       c = min(c, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1,
-                                      ((int)SERIAL_XMIT_SIZE) - info->xmit_head));
-                       local_irq_restore(flags);
-                       memcpy(info->xmit_buf + info->xmit_head, mcfrs_tmp_buf, c);
-                       up(&mcfrs_tmp_buf_sem);
-               } else
-                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
+               memcpy(info->xmit_buf + info->xmit_head, buf, c);
 
                local_irq_disable();
                info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
@@ -990,7 +979,7 @@ static void send_break(     struct mcf_serial * info, int duration)
 
        if (!info->addr)
                return;
-       current->state = TASK_INTERRUPTIBLE;
+       set_current_state(TASK_INTERRUPTIBLE);
        uartp = info->addr;
 
        local_irq_save(flags);
@@ -1242,8 +1231,7 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp)
 #endif 
        if (info->blocked_open) {
                if (info->close_delay) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(info->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
                }
                wake_up_interruptible(&info->open_wait);
        }
@@ -1308,8 +1296,7 @@ mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
                        fifo_cnt++;
                if (fifo_cnt == 0)
                        break;
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(char_time);
+               msleep_interruptible(jiffies_to_msecs(char_time));
                if (signal_pending(current))
                        break;
                if (timeout && time_after(jiffies, orig_jiffies + timeout))
index 63bb971..c03f9bf 100644 (file)
@@ -47,17 +47,18 @@ struct uart_pmac_port {
 #define PMACZILOG_FLAG_IS_OPEN         0x00002000
 #define PMACZILOG_FLAG_IS_IRQ_ON       0x00004000
 #define PMACZILOG_FLAG_IS_EXTCLK       0x00008000
+#define PMACZILOG_FLAG_BREAK           0x00010000
 
        unsigned char                   parity_mask;
        unsigned char                   prev_status;
 
-       volatile u8                     *control_reg;
-       volatile u8                     *data_reg;
+       volatile u8                     __iomem *control_reg;
+       volatile u8                     __iomem *data_reg;
 
        unsigned int                    tx_dma_irq;
        unsigned int                    rx_dma_irq;
-       volatile struct dbdma_regs      *tx_dma_regs;
-       volatile struct dbdma_regs      *rx_dma_regs;
+       volatile struct dbdma_regs      __iomem *tx_dma_regs;
+       volatile struct dbdma_regs      __iomem *rx_dma_regs;
 
        struct termios                  termios_cache;
 };
index 70d2f83..c2fa9b4 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/char/s3c2410.c
+ * linux/drivers/serial/s3c2410.c
  *
- * Driver for onboard UARTs on the Samsung S3C2410
+ * Driver for onboard UARTs on the Samsung S3C24XX
  *
  * Based on drivers/char/serial.c and drivers/char/21285.c
  *
  *
  * Changelog:
  *
- */
+ * 22-Jul-2004  BJD  Finished off device rewrite
+ *
+ * 21-Jul-2004  BJD  Thanks to <herbet@13thfloor.at> for pointing out
+ *                   problems with baud rate and loss of IR settings. Update
+ *                   to add configuration via platform_device structure
+ *
+ * 28-Sep-2004  BJD  Re-write for the following items
+ *                  - S3C2410 and S3C2440 serial support
+ *                  - Power Management support
+ *                  - Fix console via IrDA devices
+ *                  - SysReq (Herbert Pötzl)
+ *                  - Break character handling (Herbert Pötzl)
+ *                  - spin-lock initialisation (Dimitry Andric)
+ *                  - added clock control
+ *                  - updated init code to use platform_device info
+*/
+
+/* Hote on 2410 error handling
+ *
+ * The s3c2410 manual has a love/hate affair with the contents of the
+ * UERSTAT register in the UART blocks, and keeps marking some of the
+ * error bits as reserved. Having checked with the s3c2410x01,
+ * it copes with BREAKs properly, so I am happy to ignore the RESERVED
+ * feature from the latter versions of the manual.
+ *
+ * If it becomes aparrent that latter versions of the 2410 remove these
+ * bits, then action will have to be taken to differentiate the versions
+ * and change the policy on BREAK
+ *
+ * BJD, 04-Nov-2004
+*/
+
 #include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_S3C2410_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/sysrq.h>
 #include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
 #include <asm/hardware.h>
+#include <asm/hardware/clock.h>
+
 #include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+
+#include <asm/mach-types.h>
+
+/* structures */
+
+struct s3c24xx_uart_info {
+       char                    *name;
+       unsigned int            type;
+       unsigned int            fifosize;
+       unsigned long           rx_fifomask;
+       unsigned long           rx_fifoshift;
+       unsigned long           rx_fifofull;
+       unsigned long           tx_fifomask;
+       unsigned long           tx_fifoshift;
+       unsigned long           tx_fifofull;
+
+       /* clock source control */
+
+       int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
+       int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
+};
+
+struct s3c24xx_uart_port {
+       unsigned char                   rx_claimed;
+       unsigned char                   tx_claimed;
+
+       struct s3c24xx_uart_info        *info;
+       struct s3c24xx_uart_clksrc      *clksrc;
+       struct clk                      *clk;
+       struct clk                      *baudclk;
+       struct uart_port                port;
+};
+
+
+/* configuration defines */
 
 #if 0
-#include <asm/debug-ll.h>
-#define dbg(x...) llprintk(x)
+#if 1
+/* send debug to the low-level output routines */
+
+extern void printascii(const char *);
+
+static void
+s3c24xx_serial_dbg(const char *fmt, ...)
+{
+       va_list va;
+       char buff[256];
+
+       va_start(va, fmt);
+       vsprintf(buff, fmt, va);
+       va_end(va);
+
+       printascii(buff);
+}
+
+#define dbg(x...) s3c24xx_serial_dbg(x)
+
 #else
-#define dbg(x...)
+#define dbg(x...) printk(KERN_DEBUG "s3c24xx: ");
 #endif
+#else /* no debug */
+#define dbg(x...) do {} while(0)
+#endif
+
+/* UART name and device definitions */
+
+#define S3C24XX_SERIAL_NAME    "ttySAC"
+#define S3C24XX_SERIAL_DEVFS    "tts/"
+#define S3C24XX_SERIAL_MAJOR   204
+#define S3C24XX_SERIAL_MINOR   64
+
 
-#define SERIAL_S3C2410_NAME    "ttySAC"
-#define SERIAL_S3C2410_MAJOR   204
-#define SERIAL_S3C2410_MINOR   64
+/* conversion functions */
+
+#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
+#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
 
 /* we can support 3 uarts, but not always use them */
 
 #define NR_PORTS (3)
 
-static const char serial_s3c2410_name[] = "Samsung S3C2410 UART";
-
 /* port irq numbers */
 
 #define TX_IRQ(port) ((port)->irq + 1)
 #define RX_IRQ(port) ((port)->irq)
 
-#define tx_enabled(port) ((port)->unused[0])
-#define rx_enabled(port) ((port)->unused[1])
-
-/* flag to ignore all characters comming in */
-#define RXSTAT_DUMMY_READ (0x10000000)
-
-/* access functions */
+/* register access controls */
 
-#define portaddr(port, reg) ((void *)((port)->membase + (reg)))
+#define portaddr(port, reg) ((port)->membase + (reg))
 
 #define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
 #define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
@@ -67,107 +166,234 @@ static const char serial_s3c2410_name[] = "Samsung S3C2410 UART";
 #define wr_regl(port, reg, val) \
   do { __raw_writel(val, portaddr(port, reg)); } while(0)
 
+/* macros to change one thing to another */
+
+#define tx_enabled(port) ((port)->unused[0])
+#define rx_enabled(port) ((port)->unused[1])
+
+/* flag to ignore all characters comming in */
+#define RXSTAT_DUMMY_READ (0x10000000)
+
+static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
+{
+       return container_of(port, struct s3c24xx_uart_port, port);
+}
+
+/* translate a port to the device name */
+
+static inline char *s3c24xx_serial_portname(struct uart_port *port)
+{
+       return to_platform_device(port->dev)->name;
+}
+
+static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
+{
+       return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
+}
+
+static void s3c24xx_serial_rx_enable(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ucon, ufcon;
+       int count = 10000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (--count && !s3c24xx_serial_txempty_nofifo(port))
+               udelay(100);
+
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       ufcon |= S3C2410_UFCON_RESETRX;
+       wr_regl(port, S3C2410_UFCON, ufcon);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon |= S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       rx_enabled(port) = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c24xx_serial_rx_disable(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ucon;
 
+       spin_lock_irqsave(&port->lock, flags);
 
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
 
-/* code */
+       rx_enabled(port) = 0;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
 
 static void
-serial_s3c2410_stop_tx(struct uart_port *port, unsigned int tty_stop)
+s3c24xx_serial_stop_tx(struct uart_port *port, unsigned int tty_stop)
 {
        if (tx_enabled(port)) {
                disable_irq(TX_IRQ(port));
                tx_enabled(port) = 0;
+               if (port->flags & UPF_CONS_FLOW)
+                       s3c24xx_serial_rx_enable(port);
        }
 }
 
 static void
-serial_s3c2410_start_tx(struct uart_port *port, unsigned int tty_start)
+s3c24xx_serial_start_tx(struct uart_port *port, unsigned int tty_start)
 {
        if (!tx_enabled(port)) {
+               if (port->flags & UPF_CONS_FLOW)
+                       s3c24xx_serial_rx_disable(port);
+
                enable_irq(TX_IRQ(port));
                tx_enabled(port) = 1;
        }
 }
 
-static void serial_s3c2410_stop_rx(struct uart_port *port)
+
+static void s3c24xx_serial_stop_rx(struct uart_port *port)
 {
        if (rx_enabled(port)) {
-               dbg("serial_s3c2410_stop_rx: port=%p\n", port);
+               dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
                disable_irq(RX_IRQ(port));
                rx_enabled(port) = 0;
        }
 }
 
-static void serial_s3c2410_enable_ms(struct uart_port *port)
+static void s3c24xx_serial_enable_ms(struct uart_port *port)
+{
+}
+
+static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
+{
+       return to_ourport(port)->info;
+}
+
+static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
+{
+       if (port->dev == NULL)
+               return NULL;
+
+       return (struct s3c2410_uartcfg *)port->dev->platform_data;
+}
+
+static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
+                                    unsigned long ufstat)
 {
+       struct s3c24xx_uart_info *info = ourport->info;
+
+       if (ufstat & info->rx_fifofull)
+               return info->fifosize;
+
+       return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
 }
 
+
 /* ? - where has parity gone?? */
 #define S3C2410_UERSTAT_PARITY (0x1000)
 
 static irqreturn_t
-serial_s3c2410_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
+s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
 {
-       struct uart_port *port = dev_id;
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
        struct tty_struct *tty = port->info->tty;
-       unsigned int ufcon, ch, rxs, ufstat;
-       int max_count = 256;
+       unsigned int ufcon, ch, flag, ufstat, uerstat;
+       int max_count = 64;
 
        while (max_count-- > 0) {
                ufcon = rd_regl(port, S3C2410_UFCON);
                ufstat = rd_regl(port, S3C2410_UFSTAT);
 
-               if (S3C2410_UFCON_RXC(ufstat) == 0)
+               if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
                        break;
 
                if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                       tty->flip.work.func((void *)tty);
-                       if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                               printk(KERN_WARNING "TTY_DONT_FLIP set\n");
-                               goto out;
-                       }
+                       if (tty->low_latency)
+                               tty_flip_buffer_push(tty);
+
+                       /*
+                        * If this failed then we will throw away the
+                        * bytes but must do so to clear interrupts
+                        */
                }
 
+               uerstat = rd_regl(port, S3C2410_UERSTAT);
                ch = rd_regb(port, S3C2410_URXH);
 
-               *tty->flip.char_buf_ptr = ch;
-               *tty->flip.flag_buf_ptr = TTY_NORMAL;
+               if (port->flags & UPF_CONS_FLOW) {
+                       int txe = s3c24xx_serial_txempty_nofifo(port);
+
+                       if (rx_enabled(port)) {
+                               if (!txe) {
+                                       rx_enabled(port) = 0;
+                                       continue;
+                               }
+                       } else {
+                               if (txe) {
+                                       ufcon |= S3C2410_UFCON_RESETRX;
+                                       wr_regl(port, S3C2410_UFCON, ufcon);
+                                       rx_enabled(port) = 1;
+                                       goto out;
+                               }
+                               continue;
+                       }
+               }
+
+               /* insert the character into the buffer */
+
+               flag = TTY_NORMAL;
                port->icount.rx++;
 
-               rxs = rd_regb(port, S3C2410_UERSTAT) | RXSTAT_DUMMY_READ;
+               if (uerstat & S3C2410_UERSTAT_ANY) {
+                       dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
+                           ch, uerstat);
+
+                       /* check for break */
+                       if (uerstat & S3C2410_UERSTAT_BREAK) {
+                               dbg("break!\n");
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                   goto ignore_char;
+                       }
 
-               if (rxs & S3C2410_UERSTAT_ANY) {
-                       if (rxs & S3C2410_UERSTAT_FRAME)
+                       if (uerstat & S3C2410_UERSTAT_FRAME)
                                port->icount.frame++;
-                       if (rxs & S3C2410_UERSTAT_OVERRUN)
+                       if (uerstat & S3C2410_UERSTAT_OVERRUN)
                                port->icount.overrun++;
 
-                       rxs &= port->read_status_mask;
+                       uerstat &= port->read_status_mask;
 
-                       if (rxs & S3C2410_UERSTAT_PARITY)
-                               *tty->flip.flag_buf_ptr = TTY_PARITY;
-                       else if (rxs & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN))
-                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                       if (uerstat & S3C2410_UERSTAT_BREAK)
+                               flag = TTY_BREAK;
+                       else if (uerstat & S3C2410_UERSTAT_PARITY)
+                               flag = TTY_PARITY;
+                       else if (uerstat & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN))
+                               flag = TTY_FRAME;
                }
 
-               if ((rxs & port->ignore_status_mask) == 0) {
-                       tty->flip.flag_buf_ptr++;
-                       tty->flip.char_buf_ptr++;
-                       tty->flip.count++;
+               if (uart_handle_sysrq_char(port, ch, regs))
+                       goto ignore_char;
+
+               if ((uerstat & port->ignore_status_mask) == 0) {
+                       tty_insert_flip_char(tty, ch, flag);
                }
 
-               if ((rxs & S3C2410_UERSTAT_OVERRUN) &&
+               if ((uerstat & S3C2410_UERSTAT_OVERRUN) &&
                    tty->flip.count < TTY_FLIPBUF_SIZE) {
                        /*
                         * Overrun is special, since it's reported
                         * immediately, and doesn't affect the current
                         * character.
                         */
-                       *tty->flip.char_buf_ptr++ = 0;
-                       *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
-                       tty->flip.count++;
+
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
                }
+
+       ignore_char:
+               continue;
        }
        tty_flip_buffer_push(tty);
 
@@ -175,10 +401,10 @@ serial_s3c2410_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t
-serial_s3c2410_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id, struct pt_regs *regs)
 {
-       struct uart_port *port = (struct uart_port *)dev_id;
+       struct s3c24xx_uart_port *ourport = id;
+       struct uart_port *port = &ourport->port;
        struct circ_buf *xmit = &port->info->xmit;
        int count = 256;
 
@@ -194,14 +420,14 @@ serial_s3c2410_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
        */
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               serial_s3c2410_stop_tx(port, 0);
+               s3c24xx_serial_stop_tx(port, 0);
                goto out;
        }
 
        /* try and drain the buffer... */
 
        while (!uart_circ_empty(xmit) && count-- > 0) {
-               if (rd_regl(port, S3C2410_UFSTAT) & S3C2410_UFSTAT_TXFULL)
+               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
                        break;
 
                wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
@@ -213,22 +439,31 @@ serial_s3c2410_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               serial_s3c2410_stop_tx(port, 0);
+               s3c24xx_serial_stop_tx(port, 0);
 
  out:
        return IRQ_HANDLED;
 }
 
-static unsigned int
-serial_s3c2410_tx_empty(struct uart_port *port)
+static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
 {
-       unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
-       return (S3C2410_UFCON_TXC(ufcon) != 0) ? 0 : TIOCSER_TEMT;
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
+       unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
+
+       if (ufcon & S3C2410_UFCON_FIFOMODE) {
+               if ((ufstat & info->tx_fifomask) != 0 ||
+                   (ufstat & info->tx_fifofull))
+                       return 0;
+
+               return 1;
+       }
+
+       return s3c24xx_serial_txempty_nofifo(port);
 }
 
 /* no modem control lines */
-static unsigned int
-serial_s3c2410_get_mctrl(struct uart_port *port)
+static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
 {
        unsigned int umstat = rd_regb(port,S3C2410_UMSTAT);
 
@@ -238,13 +473,12 @@ serial_s3c2410_get_mctrl(struct uart_port *port)
                return TIOCM_CAR | TIOCM_DSR;
 }
 
-static void
-serial_s3c2410_set_mctrl(struct uart_port *port, unsigned int mctrl)
+static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
        /* todo - possibly remove AFC and do manual CTS */
 }
 
-static void serial_s3c2410_break_ctl(struct uart_port *port, int break_state)
+static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
 {
        unsigned long flags;
        unsigned int ucon;
@@ -263,46 +497,250 @@ static void serial_s3c2410_break_ctl(struct uart_port *port, int break_state)
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static int serial_s3c2410_startup(struct uart_port *port)
+static void s3c24xx_serial_shutdown(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (ourport->tx_claimed) {
+               free_irq(TX_IRQ(port), ourport);
+               tx_enabled(port) = 0;
+               ourport->tx_claimed = 0;
+       }
+
+       if (ourport->rx_claimed) {
+               free_irq(RX_IRQ(port), ourport);
+               ourport->rx_claimed = 0;
+               rx_enabled(port) = 0;
+       }
+}
+
+
+static int s3c24xx_serial_startup(struct uart_port *port)
 {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long flags;
        int ret;
 
-       tx_enabled(port) = 1;
-       rx_enabled(port) = 1;
+       dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
+           port->mapbase, port->membase);
 
-       dbg("serial_s3c2410_startup: port=%p (%p)\n",
-           port, port->mapbase);
+       local_irq_save(flags);
 
-       ret = request_irq(RX_IRQ(port), serial_s3c2410_rx_chars, 0,
-                         serial_s3c2410_name, port);
+       rx_enabled(port) = 1;
+
+       ret = request_irq(RX_IRQ(port),
+                         s3c24xx_serial_rx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
 
-       if (ret != 0)
+       if (ret != 0) {
+               printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port));
                return ret;
+       }
+
+       ourport->rx_claimed = 1;
 
-       ret = request_irq(TX_IRQ(port), serial_s3c2410_tx_chars, 0,
-                         serial_s3c2410_name, port);
+       dbg("requesting tx irq...\n");
+
+       tx_enabled(port) = 1;
+
+       ret = request_irq(TX_IRQ(port),
+                         s3c24xx_serial_tx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
 
        if (ret) {
-               free_irq(RX_IRQ(port), port);
-               return ret;
+               printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port));
+               goto err;
        }
 
+       ourport->tx_claimed = 1;
+
+       dbg("s3c24xx_serial_startup ok\n");
+
        /* the port reset code should have done the correct
         * register setup for the port controls */
 
+       local_irq_restore(flags);
+       return ret;
+
+ err:
+       s3c24xx_serial_shutdown(port);
+       local_irq_restore(flags);
        return ret;
 }
 
-static void serial_s3c2410_shutdown(struct uart_port *port)
+/* power power management control */
+
+static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
+                             unsigned int old)
 {
-       free_irq(TX_IRQ(port), port);
-       free_irq(RX_IRQ(port), port);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       switch (level) {
+       case 3:
+               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+                       clk_disable(ourport->baudclk);
+
+               clk_disable(ourport->clk);
+               break;
+
+       case 0:
+               clk_enable(ourport->clk);
+
+               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+                       clk_enable(ourport->baudclk);
+
+               break;
+       default:
+               printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
+       }
 }
 
-static void
-serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
-                          struct termios *old)
+/* baud rate calculation
+ *
+ * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
+ * of different sources, including the peripheral clock ("pclk") and an
+ * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
+ * with a programmable extra divisor.
+ *
+ * The following code goes through the clock sources, and calculates the
+ * baud clocks (and the resultant actual baud rates) and then tries to
+ * pick the closest one and select that.
+ *
+ * NOTES:
+ *     1) there is no current code to properly select/deselect FCLK on
+ *        the s3c2440, so only specify FCLK or non-FCLK in the clock
+ *        sources for the UART
+ *
+*/
+
+
+#define MAX_CLKS (8)
+
+static struct s3c24xx_uart_clksrc tmp_clksrc = {
+       .name           = "pclk",
+       .min_baud       = 0,
+       .max_baud       = 0,
+       .divisor        = 1,
+};
+
+static inline int
+s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       return (info->get_clksrc)(port, c);
+}
+
+static inline int
+s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       return (info->set_clksrc)(port, c);
+}
+
+struct baud_calc {
+       struct s3c24xx_uart_clksrc      *clksrc;
+       unsigned int                     calc;
+       unsigned int                     quot;
+       struct clk                      *src;
+};
+
+static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
+                                  struct uart_port *port,
+                                  struct s3c24xx_uart_clksrc *clksrc,
+                                  unsigned int baud)
+{
+       unsigned long rate;
+
+       calc->src = clk_get(port->dev, clksrc->name);
+       if (calc->src == NULL || IS_ERR(calc->src))
+               return 0;
+
+       rate = clk_get_rate(calc->src);
+
+       calc->clksrc = clksrc;
+       calc->quot = (rate + (8 * baud)) / (16 * baud);
+       calc->calc = (rate / (calc->quot * 16));
+
+       calc->quot--;
+       return 1;
+}
+
+static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
+                                         struct s3c24xx_uart_clksrc **clksrc,
+                                         struct clk **clk,
+                                         unsigned int baud)
+{
+       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+       struct s3c24xx_uart_clksrc *clkp;
+       struct baud_calc res[MAX_CLKS];
+       struct baud_calc *resptr, *best, *sptr;
+       int i;
+
+       clkp = cfg->clocks;
+       best = NULL;
+
+       if (cfg->clocks_size < 2) {
+               if (cfg->clocks_size == 0)
+                       clkp = &tmp_clksrc;
+
+               s3c24xx_serial_calcbaud(res, port, clkp, baud);
+               best = res;
+               resptr = best + 1;
+       } else {
+               resptr = res;
+
+               for (i = 0; i < cfg->clocks_size; i++, clkp++) {
+                       if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
+                               resptr++;
+               }
+       }
+
+       /* ok, we now need to select the best clock we found */
+
+       if (!best) {
+               unsigned int deviation = (1<<30)|((1<<30)-1);
+               int calc_deviation;
+
+               for (sptr = res; sptr < resptr; sptr++) {
+                       printk(KERN_DEBUG
+                              "found clk %p (%s) quot %d, calc %d\n",
+                              sptr->clksrc, sptr->clksrc->name,
+                              sptr->quot, sptr->calc);
+
+                       calc_deviation = baud - sptr->calc;
+                       if (calc_deviation < 0)
+                               calc_deviation = -calc_deviation;
+
+                       if (calc_deviation < deviation) {
+                               best = sptr;
+                               deviation = calc_deviation;
+                       }
+               }
+
+               printk(KERN_DEBUG "best %p (deviation %d)\n", best, deviation);
+       }
+
+       printk(KERN_DEBUG "selected clock %p (%s) quot %d, calc %d\n",
+              best->clksrc, best->clksrc->name, best->quot, best->calc);
+
+       /* store results to pass back */
+
+       *clksrc = best->clksrc;
+       *clk    = best->src;
+
+       return best->quot;
+}
+
+static void s3c24xx_serial_set_termios(struct uart_port *port,
+                                      struct termios *termios,
+                                      struct termios *old)
 {
+       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct s3c24xx_uart_clksrc *clksrc;
+       struct clk *clk;
        unsigned long flags;
        unsigned int baud, quot;
        unsigned int ulcon;
@@ -313,16 +751,34 @@ serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
        termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
        termios->c_cflag |= CLOCAL;
 
-       /*
-        * We don't support BREAK character recognition.
-        */
-       termios->c_iflag &= ~(IGNBRK | BRKINT);
-
        /*
         * 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);
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
+
+       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+               quot = port->custom_divisor;
+       else
+               quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
+
+       /* check to see if we need  to change clock source */
+
+       if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
+               s3c24xx_serial_setsource(port, clksrc);
+
+               if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
+                       clk_disable(ourport->baudclk);
+                       clk_unuse(ourport->baudclk);
+                       ourport->baudclk  = NULL;
+               }
+
+               clk_use(clk);
+               clk_enable(clk);
+
+               ourport->clksrc = clksrc;
+               ourport->baudclk = clk;
+       }
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
@@ -344,6 +800,9 @@ serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
                break;
        }
 
+       /* preserve original lcon IR settings */
+       ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
+
        if (termios->c_cflag & CSTOPB)
                ulcon |= S3C2410_LCON_STOPB;
 
@@ -356,18 +815,12 @@ serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
                ulcon |= S3C2410_LCON_PNONE;
        }
 
-       /*
-       if (port->fifosize)
-       enable_fifo()
-       */
-
        spin_lock_irqsave(&port->lock, flags);
 
-       dbg("setting ulcon to %08x\n", ulcon);
-       //dbg("<flushing output from serial>\n");
+       dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);
 
-       /* set the ulcon register */
        wr_regl(port, S3C2410_ULCON, ulcon);
+       wr_regl(port, S3C2410_UBRDIV, quot);
 
        dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
            rd_regl(port, S3C2410_ULCON),
@@ -404,113 +857,151 @@ serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static const char *serial_s3c2410_type(struct uart_port *port)
+static const char *s3c24xx_serial_type(struct uart_port *port)
 {
-       return port->type == PORT_S3C2410 ? "S3C2410" : NULL;
+       switch (port->type) {
+       case PORT_S3C2410:
+               return "S3C2410";
+       case PORT_S3C2440:
+               return "S3C2440";
+       default:
+               return NULL;
+       }
 }
 
 #define MAP_SIZE (0x100)
 
-static void
-serial_s3c2410_release_port(struct uart_port *port)
+static void s3c24xx_serial_release_port(struct uart_port *port)
 {
        release_mem_region(port->mapbase, MAP_SIZE);
 }
 
-static int
-serial_s3c2410_request_port(struct uart_port *port)
+static int s3c24xx_serial_request_port(struct uart_port *port)
 {
-       return request_mem_region(port->mapbase, MAP_SIZE, serial_s3c2410_name)
-               != NULL ? 0 : -EBUSY;
+       char *name = s3c24xx_serial_portname(port);
+       return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
 }
 
-static void
-serial_s3c2410_config_port(struct uart_port *port, int flags)
+static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
 {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
        if (flags & UART_CONFIG_TYPE &&
-           serial_s3c2410_request_port(port) == 0)
-               port->type = PORT_S3C2410;
+           s3c24xx_serial_request_port(port) == 0)
+               port->type = info->type;
 }
 
 /*
  * verify the new serial_struct (for TIOCSSERIAL).
  */
 static int
-serial_s3c2410_verify_port(struct uart_port *port, struct serial_struct *ser)
+s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
-       int ret = 0;
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
 
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_S3C2410)
-               ret = -EINVAL;
+       if (ser->type != PORT_UNKNOWN && ser->type != info->type)
+               return -EINVAL;
 
-       return ret;
+       return 0;
 }
 
-static struct uart_ops serial_s3c2410_ops = {
-       .tx_empty       = serial_s3c2410_tx_empty,
-       .get_mctrl      = serial_s3c2410_get_mctrl,
-       .set_mctrl      = serial_s3c2410_set_mctrl,
-       .stop_tx        = serial_s3c2410_stop_tx,
-       .start_tx       = serial_s3c2410_start_tx,
-       .stop_rx        = serial_s3c2410_stop_rx,
-       .enable_ms      = serial_s3c2410_enable_ms,
-       .break_ctl      = serial_s3c2410_break_ctl,
-       .startup        = serial_s3c2410_startup,
-       .shutdown       = serial_s3c2410_shutdown,
-       .set_termios    = serial_s3c2410_set_termios,
-       .type           = serial_s3c2410_type,
-       .release_port   = serial_s3c2410_release_port,
-       .request_port   = serial_s3c2410_request_port,
-       .config_port    = serial_s3c2410_config_port,
-       .verify_port    = serial_s3c2410_verify_port,
+
+#ifdef CONFIG_SERIAL_S3C2410_CONSOLE
+
+static struct console s3c24xx_serial_console;
+
+#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
+#else
+#define S3C24XX_SERIAL_CONSOLE NULL
+#endif
+
+static struct uart_ops s3c24xx_serial_ops = {
+       .pm             = s3c24xx_serial_pm,
+       .tx_empty       = s3c24xx_serial_tx_empty,
+       .get_mctrl      = s3c24xx_serial_get_mctrl,
+       .set_mctrl      = s3c24xx_serial_set_mctrl,
+       .stop_tx        = s3c24xx_serial_stop_tx,
+       .start_tx       = s3c24xx_serial_start_tx,
+       .stop_rx        = s3c24xx_serial_stop_rx,
+       .enable_ms      = s3c24xx_serial_enable_ms,
+       .break_ctl      = s3c24xx_serial_break_ctl,
+       .startup        = s3c24xx_serial_startup,
+       .shutdown       = s3c24xx_serial_shutdown,
+       .set_termios    = s3c24xx_serial_set_termios,
+       .type           = s3c24xx_serial_type,
+       .release_port   = s3c24xx_serial_release_port,
+       .request_port   = s3c24xx_serial_request_port,
+       .config_port    = s3c24xx_serial_config_port,
+       .verify_port    = s3c24xx_serial_verify_port,
+};
+
+
+static struct uart_driver s3c24xx_uart_drv = {
+       .owner          = THIS_MODULE,
+       .dev_name       = "s3c2410_serial",
+       .nr             = 3,
+       .cons           = S3C24XX_SERIAL_CONSOLE,
+       .driver_name    = S3C24XX_SERIAL_NAME,
+       .devfs_name     = S3C24XX_SERIAL_DEVFS,
+       .major          = S3C24XX_SERIAL_MAJOR,
+       .minor          = S3C24XX_SERIAL_MINOR,
 };
 
-static struct uart_port serial_s3c2410_ports[NR_PORTS] = {
-       {
-               .membase        = 0,
-               .mapbase        = 0,
-               .iotype         = UPIO_MEM,
-               .irq            = IRQ_S3CUART_RX0,
-               .uartclk        = 0,
-               .fifosize       = 16,
-               .ops            = &serial_s3c2410_ops,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .line           = 0,
+static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
+       [0] = {
+               .port = {
+                       .lock           = SPIN_LOCK_UNLOCKED,
+                       .membase        = 0,
+                       .mapbase        = 0,
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX0,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 0,
+               }
+       },
+       [1] = {
+               .port = {
+                       .lock           = SPIN_LOCK_UNLOCKED,
+                       .membase        = 0,
+                       .mapbase        = 0,
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX1,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 1,
+               }
        },
-       {
-               .membase        = 0,
-               .mapbase        = 0,
-               .iotype         = UPIO_MEM,
-               .irq            = IRQ_S3CUART_RX1,
-               .uartclk        = 0,
-               .fifosize       = 16,
-               .ops            = &serial_s3c2410_ops,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .line           = 1,
-       }
 #if NR_PORTS > 2
-       ,
-       {
-               .membase        = 0,
-               .mapbase        = 0,
-               .iotype         = UPIO_MEM,
-               .irq            = IRQ_S3CUART_RX2,
-               .uartclk        = 0,
-               .fifosize       = 16,
-               .ops            = &serial_s3c2410_ops,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .line           = 2,
+
+       [2] = {
+               .port = {
+                       .lock           = SPIN_LOCK_UNLOCKED,
+                       .membase        = 0,
+                       .mapbase        = 0,
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX2,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 2,
+               }
        }
 #endif
 };
 
-static int
-serial_s3c2410_resetport(struct uart_port *port,
-                        struct s3c2410_uartcfg *cfg)
+
+static int s3c24xx_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
 {
        /* ensure registers are setup */
 
-       dbg("serial_s3c2410_resetport: port=%p (%08x), cfg=%p\n",
+       dbg("s3c24xx_serial_resetport: port=%p (%08lx), cfg=%p\n",
            port, port->mapbase, cfg);
 
        wr_regl(port, S3C2410_UCON,  cfg->ucon);
@@ -524,105 +1015,431 @@ serial_s3c2410_resetport(struct uart_port *port,
        return 0;
 }
 
-/* serial_s3c2410_init_ports
+/* s3c24xx_serial_init_port
  *
- * initialise the serial ports from the machine provided initialisation
- * data.
-*/
+ * initialise a single serial port from the platform device given
+ */
 
-static int serial_s3c2410_init_ports(void)
+static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
+                                   struct s3c24xx_uart_info *info,
+                                   struct platform_device *platdev)
 {
-       struct uart_port *ptr = serial_s3c2410_ports;
-       struct s3c2410_uartcfg *cfg = s3c2410_uartcfgs;
-       static int inited = 0;
-       int i;
+       struct uart_port *port = &ourport->port;
+       struct s3c2410_uartcfg *cfg;
+       struct resource *res;
+
+       dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
+
+       if (platdev == NULL)
+               return -ENODEV;
 
-       if (inited)
+       cfg = s3c24xx_dev_to_cfg(&platdev->dev);
+
+       if (port->mapbase != 0)
                return 0;
-       inited = 1;
 
-       dbg("serial_s3c2410_init_ports: initialising ports...\n");
+       if (cfg->hwport > 3)
+               return -EINVAL;
 
-       for (i = 0; i < NR_PORTS; i++, ptr++, cfg++) {
+       /* setup info for port */
+       port->dev       = &platdev->dev;
+       ourport->info   = info;
 
-               if (cfg->hwport > 3)
-                       continue;
+       /* copy the info in from provided structure */
+       ourport->port.fifosize = info->fifosize;
 
-               dbg("serial_s3c2410_init_ports: port %d (hw %d)...\n",
-                   i, cfg->hwport);
+       dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
 
-               if (cfg->clock != NULL)
-                       ptr->uartclk = *cfg->clock;
+       port->uartclk = 1;
 
-               switch (cfg->hwport) {
-               case 0:
-                       ptr->mapbase = S3C2410_PA_UART0;
-                       ptr->membase = (char *)S3C2410_VA_UART0;
-                       ptr->irq     = IRQ_S3CUART_RX0;
-                       break;
+       if (cfg->uart_flags & UPF_CONS_FLOW) {
+               dbg("s3c24xx_serial_init_port: enabling flow control\n");
+               port->flags |= UPF_CONS_FLOW;
+       }
 
-               case 1:
-                       ptr->mapbase = S3C2410_PA_UART1;
-                       ptr->membase = (char *)S3C2410_VA_UART1;
-                       ptr->irq     = IRQ_S3CUART_RX1;
-                       break;
+       /* sort our the physical and virtual addresses for each UART */
 
-               case 2:
-                       ptr->mapbase = S3C2410_PA_UART2;
-                       ptr->membase = (char *)S3C2410_VA_UART2;
-                       ptr->irq     = IRQ_S3CUART_RX2;
-                       break;
-               }
+       res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               printk(KERN_ERR "failed to find memory resource for uart\n");
+               return -EINVAL;
+       }
+
+       dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
+
+       port->mapbase   = res->start;
+       port->membase   = (void __iomem *)(res->start - S3C2410_PA_UART);
+       port->membase  += S3C2410_VA_UART;
+       port->irq       = platform_get_irq(platdev, 0);
+
+       ourport->clk    = clk_get(&platdev->dev, "uart");
+
+       if (ourport->clk != NULL && !IS_ERR(ourport->clk))
+               clk_use(ourport->clk);
+
+       dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld\n",
+           port->mapbase, port->membase, port->irq, port->uartclk);
+
+       /* reset the fifos (and setup the uart) */
+       s3c24xx_serial_resetport(port, cfg);
+       return 0;
+}
+
+/* Device driver serial port probe */
+
+static int probe_index = 0;
+
+int s3c24xx_serial_probe(struct device *_dev,
+                        struct s3c24xx_uart_info *info)
+{
+       struct s3c24xx_uart_port *ourport;
+       struct platform_device *dev = to_platform_device(_dev);
+       int ret;
+
+       dbg("s3c24xx_serial_probe(%p, %p) %d\n", _dev, info, probe_index);
+
+       ourport = &s3c24xx_serial_ports[probe_index];
+       probe_index++;
+
+       dbg("%s: initialising port %p...\n", __FUNCTION__, ourport);
+
+       ret = s3c24xx_serial_init_port(ourport, info, dev);
+       if (ret < 0)
+               goto probe_err;
+
+       dbg("%s: adding port\n", __FUNCTION__);
+       uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
+       dev_set_drvdata(_dev, &ourport->port);
+
+       return 0;
 
-               if (ptr->mapbase == 0)
-                       continue;
+ probe_err:
+       return ret;
+}
+
+int s3c24xx_serial_remove(struct device *_dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(_dev);
+
+       if (port)
+               uart_remove_one_port(&s3c24xx_uart_drv, port);
+
+       return 0;
+}
+
+/* UART power management code */
+
+#ifdef CONFIG_PM
+
+int s3c24xx_serial_suspend(struct device *dev, u32 state, u32 level)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(dev);
+
+       if (port && level == SUSPEND_DISABLE)
+               uart_suspend_port(&s3c24xx_uart_drv, port);
+
+       return 0;
+}
 
-               /* reset the fifos (and setup the uart */
-               serial_s3c2410_resetport(ptr, cfg);
+int s3c24xx_serial_resume(struct device *dev, u32 level)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(dev);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (port && level == RESUME_ENABLE) {
+               clk_enable(ourport->clk);
+               s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
+               clk_disable(ourport->clk);
+
+               uart_resume_port(&s3c24xx_uart_drv, port);
        }
 
        return 0;
 }
 
+#else
+#define s3c24xx_serial_suspend NULL
+#define s3c24xx_serial_resume  NULL
+#endif
+
+int s3c24xx_serial_init(struct device_driver *drv,
+                       struct s3c24xx_uart_info *info)
+{
+       dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
+       return driver_register(drv);
+}
+
+
+/* now comes the code to initialise either the s3c2410 or s3c2440 serial
+ * port information
+*/
+
+/* cpu specific variations on the serial port support */
+
+#ifdef CONFIG_CPU_S3C2410
+
+static int s3c2410_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2410_UCON_UCLK;
+       else
+               ucon &= ~S3C2410_UCON_UCLK;
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+static int s3c2410_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c2410_uart_inf = {
+       .name           = "Samsung S3C2410 UART",
+       .type           = PORT_S3C2410,
+       .fifosize       = 16,
+       .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2410_serial_getsource,
+       .set_clksrc     = s3c2410_serial_setsource,
+};
+
+/* device management */
+
+static int s3c2410_serial_probe(struct device *dev)
+{
+       return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
+}
+
+static struct device_driver s3c2410_serial_drv = {
+       .name           = "s3c2410-uart",
+       .bus            = &platform_bus_type,
+       .probe          = s3c2410_serial_probe,
+       .remove         = s3c24xx_serial_remove,
+       .suspend        = s3c24xx_serial_suspend,
+       .resume         = s3c24xx_serial_resume,
+};
+
+static inline int s3c2410_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf);
+}
+
+static inline void s3c2410_serial_exit(void)
+{
+       driver_unregister(&s3c2410_serial_drv);
+}
+
+#define s3c2410_uart_inf_at &s3c2410_uart_inf
+#else
+
+static inline int s3c2410_serial_init(void)
+{
+       return 0;
+}
+
+static inline void s3c2410_serial_exit(void)
+{
+}
+
+#define s3c2410_uart_inf_at NULL
+
+#endif /* CONFIG_CPU_S3C2410 */
+
+#ifdef CONFIG_CPU_S3C2440
+
+static int s3c2440_serial_setsource(struct uart_port *port,
+                                    struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       // todo - proper fclk<>nonfclk switch //
+
+       ucon &= ~S3C2440_UCON_CLKMASK;
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2440_UCON_UCLK;
+       else if (strcmp(clk->name, "pclk") == 0)
+               ucon |= S3C2440_UCON_PCLK;
+       else if (strcmp(clk->name, "fclk") == 0)
+               ucon |= S3C2440_UCON_FCLK;
+       else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s3c2440_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       switch (ucon & S3C2440_UCON_CLKMASK) {
+       case S3C2440_UCON_UCLK:
+               clk->divisor = 1;
+               clk->name = "uclk";
+               break;
+
+       case S3C2440_UCON_PCLK:
+       case S3C2440_UCON_PCLK2:
+               clk->divisor = 1;
+               clk->name = "pclk";
+               break;
+
+       case S3C2440_UCON_FCLK:
+               clk->divisor = 7; /* todo - work out divisor */
+               clk->name = "fclk";
+               break;
+       }
+
+       return 0;
+}
+
+
+static struct s3c24xx_uart_info s3c2440_uart_inf = {
+       .name           = "Samsung S3C2440 UART",
+       .type           = PORT_S3C2440,
+       .fifosize       = 64,
+       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2440_serial_getsource,
+       .set_clksrc     = s3c2440_serial_setsource
+};
+
+/* device management */
+
+static int s3c2440_serial_probe(struct device *dev)
+{
+       dbg("s3c2440_serial_probe: dev=%p\n", dev);
+       return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
+}
+
+static struct device_driver s3c2440_serial_drv = {
+       .name           = "s3c2440-uart",
+       .bus            = &platform_bus_type,
+       .probe          = s3c2440_serial_probe,
+       .remove         = s3c24xx_serial_remove,
+       .suspend        = s3c24xx_serial_suspend,
+       .resume         = s3c24xx_serial_resume,
+};
+
+
+static inline int s3c2440_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2440_serial_drv, &s3c2440_uart_inf);
+}
+
+static inline void s3c2440_serial_exit(void)
+{
+       driver_unregister(&s3c2440_serial_drv);
+}
+
+#define s3c2440_uart_inf_at &s3c2440_uart_inf
+#else
+
+static inline int s3c2440_serial_init(void)
+{
+       return 0;
+}
+
+static inline void s3c2440_serial_exit(void)
+{
+}
+
+#define s3c2440_uart_inf_at NULL
+#endif /* CONFIG_CPU_S3C2440 */
+
+/* module initialisation code */
+
+static int __init s3c24xx_serial_modinit(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&s3c24xx_uart_drv);
+       if (ret < 0) {
+               printk(KERN_ERR "failed to register UART driver\n");
+               return -1;
+       }
+
+       s3c2410_serial_init();
+       s3c2440_serial_init();
+
+       return 0;
+}
+
+static void __exit s3c24xx_serial_modexit(void)
+{
+       s3c2410_serial_exit();
+       s3c2440_serial_exit();
+
+       uart_unregister_driver(&s3c24xx_uart_drv);
+}
+
+
+module_init(s3c24xx_serial_modinit);
+module_exit(s3c24xx_serial_modexit);
+
+/* Console code */
+
 #ifdef CONFIG_SERIAL_S3C2410_CONSOLE
 
 static struct uart_port *cons_uart;
 
 static int
-serial_s3c2410_console_txrdy(struct uart_port *port, unsigned int ufcon)
+s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
 {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
        unsigned long ufstat, utrstat;
 
        if (ufcon & S3C2410_UFCON_FIFOMODE) {
                /* fifo mode - check ammount of data in fifo registers... */
 
                ufstat = rd_regl(port, S3C2410_UFSTAT);
-
-               return S3C2410_UFCON_TXC(ufstat) < 12;
+               return (ufstat & info->tx_fifofull) ? 0 : 1;
        }
 
        /* in non-fifo mode, we go and use the tx buffer empty */
 
        utrstat = rd_regl(port, S3C2410_UTRSTAT);
-
-       return (utrstat & S3C2410_UTRSTAT_TXFE) ? 1 : 0;
+       return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
 }
 
 static void
-serial_s3c2410_console_write(struct console *co, const char *s,
+s3c24xx_serial_console_write(struct console *co, const char *s,
                             unsigned int count)
 {
        int i;
        unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
 
        for (i = 0; i < count; i++) {
-               while (!serial_s3c2410_console_txrdy(cons_uart, ufcon))
+               while (!s3c24xx_serial_console_txrdy(cons_uart, ufcon))
                        barrier();
 
                wr_regb(cons_uart, S3C2410_UTXH, s[i]);
 
                if (s[i] == '\n') {
-                       while (!serial_s3c2410_console_txrdy(cons_uart, ufcon))
+                       while (!s3c24xx_serial_console_txrdy(cons_uart, ufcon))
                                barrier();
 
                        wr_regb(cons_uart, S3C2410_UTXH, '\r');
@@ -631,17 +1448,21 @@ serial_s3c2410_console_write(struct console *co, const char *s,
 }
 
 static void __init
-serial_s3c2410_get_options(struct uart_port *port, int *baud,
+s3c24xx_serial_get_options(struct uart_port *port, int *baud,
                           int *parity, int *bits)
 {
-
-       unsigned int ulcon, ucon, ubrdiv;
+       struct s3c24xx_uart_clksrc clksrc;
+       struct clk *clk;
+       unsigned int ulcon;
+       unsigned int ucon;
+       unsigned int ubrdiv;
+       unsigned long rate;
 
        ulcon  = rd_regl(port, S3C2410_ULCON);
        ucon   = rd_regl(port, S3C2410_UCON);
        ubrdiv = rd_regl(port, S3C2410_UBRDIV);
 
-       dbg("serial_s3c2410_get_options: port=%p\n"
+       dbg("s3c24xx_serial_get_options: port=%p\n"
            "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
            port, ulcon, ucon, ubrdiv);
 
@@ -673,21 +1494,53 @@ serial_s3c2410_get_options(struct uart_port *port, int *baud,
                        *parity = 'o';
                        break;
 
-               default:
                case S3C2410_LCON_PNONE:
+               default:
                        *parity = 'n';
                }
 
                /* now calculate the baud rate */
 
-               *baud = port->uartclk / ( 16 * (ubrdiv + 1));
+               s3c24xx_serial_getsource(port, &clksrc);
+
+               clk = clk_get(port->dev, clksrc.name);
+               if (!IS_ERR(clk) && clk != NULL)
+                       rate = clk_get_rate(clk);
+               else
+                       rate = 1;
+
+
+               *baud = rate / ( 16 * (ubrdiv + 1));
                dbg("calculated baud %d\n", *baud);
        }
 
 }
 
+/* s3c24xx_serial_init_ports
+ *
+ * initialise the serial ports from the machine provided initialisation
+ * data.
+*/
+
+static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info *info)
+{
+       struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
+       struct platform_device **platdev_ptr;
+       int i;
+
+       dbg("s3c24xx_serial_init_ports: initialising ports...\n");
+
+       platdev_ptr = s3c24xx_uart_devs;
+
+       for (i = 0; i < NR_PORTS; i++, ptr++, platdev_ptr++) {
+               s3c24xx_serial_init_port(ptr, info, *platdev_ptr);
+       }
+
+       return 0;
+}
+
 static int __init
-serial_s3c2410_console_setup(struct console *co, char *options)
+s3c24xx_serial_console_setup(struct console *co, char *options)
 {
        struct uart_port *port;
        int baud = 9600;
@@ -695,23 +1548,26 @@ serial_s3c2410_console_setup(struct console *co, char *options)
        int parity = 'n';
        int flow = 'n';
 
+       dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
+           co, co->index, options);
+
        /* is this a valid port */
 
        if (co->index == -1 || co->index >= NR_PORTS)
                co->index = 0;
 
-       port = &serial_s3c2410_ports[co->index];
+       port = &s3c24xx_serial_ports[co->index].port;
 
        /* is the port configured? */
 
        if (port->mapbase == 0x0) {
                co->index = 0;
-               port = &serial_s3c2410_ports[co->index];
+               port = &s3c24xx_serial_ports[co->index].port;
        }
 
        cons_uart = port;
 
-       dbg("serial_s3c2410_console_setup: port=%p (%d)\n", port, co->index);
+       dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
 
        /*
         * Check whether an invalid uart number has been specified, and
@@ -721,138 +1577,68 @@ serial_s3c2410_console_setup(struct console *co, char *options)
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
        else
-               serial_s3c2410_get_options(port, &baud, &parity, &bits);
+               s3c24xx_serial_get_options(port, &baud, &parity, &bits);
+
+       dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
 
        return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
-static struct uart_driver s3c2410_uart_drv;
+/* s3c24xx_serial_initconsole
+ *
+ * initialise the console from one of the uart drivers
+*/
 
-static struct console serial_s3c2410_console =
+static struct console s3c24xx_serial_console =
 {
-       .name           = SERIAL_S3C2410_NAME,
-       .write          = serial_s3c2410_console_write,
+       .name           = S3C24XX_SERIAL_NAME,
        .device         = uart_console_device,
-       .setup          = serial_s3c2410_console_setup,
        .flags          = CON_PRINTBUFFER,
        .index          = -1,
-       .data           = &s3c2410_uart_drv,
+       .write          = s3c24xx_serial_console_write,
+       .setup          = s3c24xx_serial_console_setup
 };
 
-static int __init s3c2410_console_init(void)
-{
-       dbg("s3c2410_console_init:\n");
-
-       serial_s3c2410_init_ports();
-       register_console(&serial_s3c2410_console);
-       return 0;
-}
-console_initcall(s3c2410_console_init);
-
-#define SERIAL_S3C2410_CONSOLE &serial_s3c2410_console
-#else
-#define SERIAL_S3C2410_CONSOLE NULL
-#endif
 
-static struct uart_driver s3c2410_uart_drv = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = SERIAL_S3C2410_NAME,
-       .dev_name               = SERIAL_S3C2410_NAME,
-       .major                  = SERIAL_S3C2410_MAJOR,
-       .minor                  = SERIAL_S3C2410_MINOR,
-       .nr                     = 3,
-       .cons                   = SERIAL_S3C2410_CONSOLE,
-};
-
-/* device driver */
-
-static int s3c2410_serial_probe(struct device *_dev);
-static int s3c2410_serial_remove(struct device *_dev);
-
-static struct device_driver s3c2410_serial_drv = {
-       .name           = "s3c2410-uart",
-       .bus            = &platform_bus_type,
-       .probe          = s3c2410_serial_probe,
-       .remove         = s3c2410_serial_remove,
-       .suspend        = NULL,
-       .resume         = NULL,
-};
-
-#define s3c2410_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
-
-static int s3c2410_serial_probe(struct device *_dev)
+static int s3c24xx_serial_initconsole(void)
 {
-       struct platform_device *dev = to_platform_device(_dev);
-       struct resource *res = dev->resource;
-       int i;
-
-       dbg("s3c2410_serial_probe: dev=%p, _dev=%p, res=%p\n", _dev, dev, res);
-
-       for (i = 0; i < dev->num_resources; i++, res++)
-               if (res->flags & IORESOURCE_MEM)
-                       break;
+       struct s3c24xx_uart_info *info;
+       struct platform_device *dev = s3c24xx_uart_devs[0];
 
-       if (i < dev->num_resources) {
-               struct uart_port *ptr = serial_s3c2410_ports;
+       dbg("s3c24xx_serial_initconsole\n");
 
-               for (i = 0; i < NR_PORTS; i++, ptr++) {
-                       dbg("s3c2410_serial_probe: ptr=%p (%08x, %08x)\n",
-                           ptr, ptr->mapbase, ptr->membase);
+       /* select driver based on the cpu */
 
-                       if (ptr->mapbase != res->start)
-                               continue;
-
-                       dbg("s3c2410_serial_probe: got device %p: port=%p\n",
-                           _dev, ptr);
-
-                       uart_add_one_port(&s3c2410_uart_drv, ptr);
-                       dev_set_drvdata(_dev, ptr);
-                       break;
-               }
+       if (dev == NULL) {
+               printk(KERN_ERR "s3c24xx: no devices for console init\n");
+               return 0;
        }
 
-       return 0;
-}
+       if (strcmp(dev->name, "s3c2410-uart") == 0) {
+               info = s3c2410_uart_inf_at;
+       } else if (strcmp(dev->name, "s3c2440-uart") == 0) {
+               info = s3c2440_uart_inf_at;
+       } else {
+               printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name);
+               return 0;
+       }
 
-static int s3c2410_serial_remove(struct device *_dev)
-{
-       struct uart_port *port = s3c2410_dev_to_port(_dev);
+       if (info == NULL) {
+               printk(KERN_ERR "s3c24xx: no driver for console\n");
+               return 0;
+       }
 
-       if (port)
-               uart_remove_one_port(&s3c2410_uart_drv, port);
+       s3c24xx_serial_console.data = &s3c24xx_uart_drv;
+       s3c24xx_serial_init_ports(info);
 
+       register_console(&s3c24xx_serial_console);
        return 0;
 }
 
+console_initcall(s3c24xx_serial_initconsole);
 
-
-static int __init serial_s3c2410_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "S3C2410X Serial, (c) 2003 Simtec Electronics\n");
-
-       ret = uart_register_driver(&s3c2410_uart_drv);
-       if (ret != 0)
-               return ret;
-
-       ret = driver_register(&s3c2410_serial_drv);
-       if (ret) {
-               uart_unregister_driver(&s3c2410_uart_drv);
-       }
-
-       return ret;
-}
-
-static void __exit serial_s3c2410_exit(void)
-{
-       driver_unregister(&s3c2410_serial_drv);
-       uart_unregister_driver(&s3c2410_uart_drv);
-}
-
-module_init(serial_s3c2410_init);
-module_exit(serial_s3c2410_exit);
+#endif /* CONFIG_SERIAL_S3C2410_CONSOLE */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C2410X (S3C2410) Serial driver");
+MODULE_DESCRIPTION("Samsung S3C2410/S3C2440 Serial port driver");
index b60c5b6..91d2087 100644 (file)
  *
  */
 #include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/serial.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>
 #include <asm/mach/serial_sa1100.h>
 
-#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
 /* We've been assigned a range on the "Low-density serial ports" major */
 #define SERIAL_SA1100_MAJOR    204
 #define MINOR_START            5
@@ -220,9 +221,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
                        goto ignore_char;
 
        error_return:
-               *tty->flip.flag_buf_ptr++ = flg;
-               *tty->flip.char_buf_ptr++ = ch;
-               tty->flip.count++;
+               tty_insert_flip_char(tty, ch, flg);
        ignore_char:
                status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
                         UTSR0_TO_SM(UART_GET_UTSR0(sport));
@@ -257,11 +256,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
                 * overrun does *not* affect the character
                 * we read from the FIFO
                 */
-               *tty->flip.flag_buf_ptr++ = flg;
-               *tty->flip.char_buf_ptr++ = ch;
-               tty->flip.count++;
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                       goto ignore_char;
+               tty_insert_flip_char(tty, ch, flg);
                ch = 0;
                flg = TTY_OVERRUN;
        }
index 8557ed1..6be72e5 100644 (file)
@@ -40,8 +40,6 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/major.h>
 #include <asm/io.h>
@@ -59,7 +57,7 @@
 
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
+module_param(pc_debug, int, 0644);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version = "serial_cs.c 1.134 2002/05/04 05:48:53 (David Hinds)";
 #else
@@ -81,7 +79,7 @@ static int do_sound = 1;
 static int buggy_uart;
 
 module_param(irq_mask, uint, 0444);
-module_param_array(irq_list, int, irq_list_count, 0444);
+module_param_array(irq_list, int, &irq_list_count, 0444);
 module_param(do_sound, int, 0444);
 module_param(buggy_uart, int, 0444);
 
@@ -148,7 +146,7 @@ static void serial_remove(dev_link_t *link)
         */
        if (info->link.state & DEV_CONFIG) {
                for (i = 0; i < info->ndev; i++)
-                       unregister_serial(info->line[i]);
+                       serial8250_unregister_port(info->line[i]);
 
                info->link.dev = NULL;
 
@@ -304,21 +302,22 @@ static void serial_detach(dev_link_t * link)
 
 /*====================================================================*/
 
-static int setup_serial(struct serial_info * info, ioaddr_t port, int irq)
+static int setup_serial(struct serial_info * info, ioaddr_t iobase, int irq)
 {
-       struct serial_struct serial;
+       struct uart_port port;
        int line;
 
-       memset(&serial, 0, sizeof (serial));
-       serial.port = port;
-       serial.irq = irq;
-       serial.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ;
+       memset(&port, 0, sizeof (struct uart_port));
+       port.iobase = iobase;
+       port.irq = irq;
+       port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+       port.uartclk = 1843200;
        if (buggy_uart)
-               serial.flags |= UPF_BUGGY_UART;
-       line = register_serial(&serial);
+               port.flags |= UPF_BUGGY_UART;
+       line = serial8250_register_port(&port);
        if (line < 0) {
-               printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
-                      " irq %d failed\n", (u_long) serial.port, serial.irq);
+               printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
+                      "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
                return -EINVAL;
        }
 
index d863368..4ce3a41 100644 (file)
  */
 
 #include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/serial.h>
 #include <linux/console.h>
 #include <linux/sysrq.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>
 
-#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include <asm/arch/serial.h>
-
 #define DEV_MAJOR      204
 #define DEV_MINOR      16
 #define DEV_NR         3
 
 #define UART_REG_SIZE  32
 
+#define UART_R_DATA    (0x00)
+#define UART_R_FCON    (0x04)
+#define UART_R_BRCON   (0x08)
+#define UART_R_CON     (0x0c)
+#define UART_R_STATUS  (0x10)
+#define UART_R_RAWISR  (0x14)
+#define UART_R_INTEN   (0x18)
+#define UART_R_ISR     (0x1c)
+
 #define UARTEN         (0x01)          /* UART enable */
 #define SIRDIS         (0x02)          /* Serial IR disable (UART1 only) */
 
@@ -138,21 +146,20 @@ lh7a40xuart_rx_chars (struct uart_port* port)
 {
        struct tty_struct* tty = port->info->tty;
        int cbRxMax = 256;      /* (Gross) limit on receive */
-       unsigned int data;      /* Received data and status */
+       unsigned int data, flag;/* Received data and status */
 
        while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
                if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                       tty->flip.work.func((void*)tty);
-                       if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                               printk(KERN_WARNING "TTY_DONT_FLIP set\n");
-                               return;
-                       }
+                       if (tty->low_latency)
+                               tty_flip_buffer_push(tty);
+                       /*
+                        * If this failed then we will throw away the
+                        * bytes but must do so to clear interrupts
+                        */
                }
 
                data = UR (port, UART_R_DATA);
-
-               *tty->flip.char_buf_ptr = (unsigned char) data;
-               *tty->flip.flag_buf_ptr = TTY_NORMAL;
+               flag = TTY_NORMAL;
                ++port->icount.rx;
 
                if (data & RxError) {   /* Quick check, short-circuit */
@@ -173,20 +180,18 @@ lh7a40xuart_rx_chars (struct uart_port* port)
                        data &= port->read_status_mask | 0xff;
 
                        if (data & RxBreak)
-                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                               flag = TTY_BREAK;
                        else if (data & RxParityError)
-                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                               flag = TTY_PARITY;
                        else if (data & RxFramingError)
-                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               flag = TTY_FRAME;
                }
 
                if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
                        continue;
 
                if ((data & port->ignore_status_mask) == 0) {
-                       ++tty->flip.flag_buf_ptr;
-                       ++tty->flip.char_buf_ptr;
-                       ++tty->flip.count;
+                       tty_insert_flip_char(tty, data, flag);
                }
                if ((data & RxOverrunError)
                    && tty->flip.count < TTY_FLIPBUF_SIZE) {
@@ -195,9 +200,7 @@ lh7a40xuart_rx_chars (struct uart_port* port)
                         * immediately, and doesn't affect the current
                         * character
                         */
-                       *tty->flip.char_buf_ptr++ = 0;
-                       *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
-                       ++tty->flip.count;
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
                }
        }
        tty_flip_buffer_push (tty);
index 200bbce..92e69e2 100644 (file)
@@ -52,7 +52,6 @@
 
 #include <asm/io.h>
 #include <asm/sn/simulator.h>
-#include <asm/sn/sn2/sn_private.h>
 #include <asm/sn/sn_sal.h>
 
 /* number of characters we can transmit to the SAL console at a time */
 
 /* To use dynamic numbers only and not use the assigned major and minor,
  * define the following.. */
-/* #define USE_DYNAMIC_MINOR 1 */ /* use dynamic minor number */
-#define USE_DYNAMIC_MINOR 0 /* Don't rely on misc_register dynamic minor */
+                                 /* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */
+#define USE_DYNAMIC_MINOR 0    /* Don't rely on misc_register dynamic minor */
 
 /* Device name we're using */
 #define DEVICE_NAME "ttySG"
-#define DEVICE_NAME_DYNAMIC "ttySG0"  /* need full name for misc_register */
+#define DEVICE_NAME_DYNAMIC "ttySG0"   /* need full name for misc_register */
 /* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */
 #define DEVICE_MAJOR 204
 #define DEVICE_MINOR 40
@@ -107,9 +106,8 @@ struct sn_cons_port {
 static struct sn_cons_port sal_console_port;
 
 /* Only used if USE_DYNAMIC_MINOR is set to 1 */
-static struct miscdevice misc; /* used with misc_register for dynamic */
+static struct miscdevice misc; /* used with misc_register for dynamic */
 
-extern u64 master_node_bedrock_address;
 extern void early_sn_setup(void);
 
 #undef DEBUG
@@ -125,9 +123,6 @@ static int snt_hw_puts_raw(const char *, int);
 static int snt_hw_puts_buffered(const char *, int);
 static int snt_poll_getc(void);
 static int snt_poll_input_pending(void);
-static int snt_sim_puts(const char *, int);
-static int snt_sim_getc(void);
-static int snt_sim_input_pending(void);
 static int snt_intr_getc(void);
 static int snt_intr_input_pending(void);
 static void sn_transmit_chars(struct sn_cons_port *, int);
@@ -141,14 +136,6 @@ static struct sn_sal_ops poll_ops = {
        .sal_input_pending = snt_poll_input_pending
 };
 
-/* A table for the simulator */
-static struct sn_sal_ops sim_ops = {
-       .sal_puts_raw = snt_sim_puts,
-       .sal_puts = snt_sim_puts,
-       .sal_getc = snt_sim_getc,
-       .sal_input_pending = snt_sim_input_pending
-};
-
 /* A table for interrupts enabled */
 static struct sn_sal_ops intr_ops = {
        .sal_puts_raw = snt_hw_puts_raw,
@@ -169,15 +156,13 @@ static struct sn_sal_ops intr_ops = {
  * output is buffered and sent to the SAL asynchronously (either by
  * timer callback or by UART interrupt) */
 
-
 /* routines for running the console in polling mode */
 
 /**
  * snt_poll_getc - Get a character from the console in polling mode
  *
  */
-static int
-snt_poll_getc(void)
+static int snt_poll_getc(void)
 {
        int ch;
 
@@ -189,8 +174,7 @@ snt_poll_getc(void)
  * snt_poll_input_pending - Check if any input is waiting - polling mode.
  *
  */
-static int
-snt_poll_input_pending(void)
+static int snt_poll_input_pending(void)
 {
        int status, input;
 
@@ -198,64 +182,13 @@ snt_poll_input_pending(void)
        return !status && input;
 }
 
-/* routines for running the console on the simulator */
-
-/**
- * snt_sim_puts - send to the console, used in simulator mode
- * @str: String to send
- * @count: length of string
- *
- */
-static int
-snt_sim_puts(const char *str, int count)
-{
-       int counter = count;
-
-#ifdef FLAG_DIRECT_CONSOLE_WRITES
-       /* This is an easy way to pre-pend the output to know whether the output
-        * was done via sal or directly */
-       writeb('[', master_node_bedrock_address + (UART_TX << 3));
-       writeb('+', master_node_bedrock_address + (UART_TX << 3));
-       writeb(']', master_node_bedrock_address + (UART_TX << 3));
-       writeb(' ', master_node_bedrock_address + (UART_TX << 3));
-#endif                         /* FLAG_DIRECT_CONSOLE_WRITES */
-       while (counter > 0) {
-               writeb(*str, master_node_bedrock_address + (UART_TX << 3));
-               counter--;
-               str++;
-       }
-       return count;
-}
-
-/**
- * snt_sim_getc - Get character from console in simulator mode
- *
- */
-static int
-snt_sim_getc(void)
-{
-       return readb(master_node_bedrock_address + (UART_RX << 3));
-}
-
-/**
- * snt_sim_input_pending - Check if there is input pending in simulator mode
- *
- */
-static int
-snt_sim_input_pending(void)
-{
-       return readb(master_node_bedrock_address +
-                    (UART_LSR << 3)) & UART_LSR_DR;
-}
-
 /* routines for an interrupt driven console (normal) */
 
 /**
  * snt_intr_getc - Get a character from the console, interrupt mode
  *
  */
-static int
-snt_intr_getc(void)
+static int snt_intr_getc(void)
 {
        return ia64_sn_console_readc();
 }
@@ -264,8 +197,7 @@ snt_intr_getc(void)
  * snt_intr_input_pending - Check if input is pending, interrupt mode
  *
  */
-static int
-snt_intr_input_pending(void)
+static int snt_intr_input_pending(void)
 {
        return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
 }
@@ -278,8 +210,7 @@ snt_intr_input_pending(void)
  * @len: Length
  *
  */
-static int
-snt_hw_puts_raw(const char *s, int len)
+static int snt_hw_puts_raw(const char *s, int len)
 {
        /* this will call the PROM and not return until this is done */
        return ia64_sn_console_putb(s, len);
@@ -291,8 +222,7 @@ snt_hw_puts_raw(const char *s, int len)
  * @len: Length
  *
  */
-static int
-snt_hw_puts_buffered(const char *s, int len)
+static int snt_hw_puts_buffered(const char *s, int len)
 {
        /* queue data to the PROM */
        return ia64_sn_console_xmit_chars((char *)s, len);
@@ -310,8 +240,7 @@ snt_hw_puts_buffered(const char *s, int len)
  * @port: Port to operate with (we ignore since we only have one port)
  *
  */
-static const char *
-snp_type(struct uart_port *port)
+static const char *snp_type(struct uart_port *port)
 {
        return ("SGI SN L1");
 }
@@ -321,8 +250,7 @@ snp_type(struct uart_port *port)
  * @port: Port to operate on (we ignore since we only have one port)
  *
  */
-static unsigned int
-snp_tx_empty(struct uart_port *port)
+static unsigned int snp_tx_empty(struct uart_port *port)
 {
        return 1;
 }
@@ -333,8 +261,7 @@ snp_tx_empty(struct uart_port *port)
  * @tty_stop: Set to 1 if called via uart_stop
  *
  */
-static void
-snp_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void snp_stop_tx(struct uart_port *port, unsigned int tty_stop)
 {
 }
 
@@ -343,8 +270,7 @@ snp_stop_tx(struct uart_port *port, unsigned int tty_stop)
  * @port: Port to operate on - we ignore - no-op function
  *
  */
-static void
-snp_release_port(struct uart_port *port)
+static void snp_release_port(struct uart_port *port)
 {
 }
 
@@ -353,8 +279,7 @@ snp_release_port(struct uart_port *port)
  * @port: Port to operate on - we ignore - no-op function
  *
  */
-static void
-snp_enable_ms(struct uart_port *port)
+static void snp_enable_ms(struct uart_port *port)
 {
 }
 
@@ -363,8 +288,7 @@ snp_enable_ms(struct uart_port *port)
  * @port: Port to shut down - we ignore
  *
  */
-static void
-snp_shutdown(struct uart_port *port)
+static void snp_shutdown(struct uart_port *port)
 {
 }
 
@@ -374,8 +298,7 @@ snp_shutdown(struct uart_port *port)
  * @mctrl: Lines to set/unset - we ignore
  *
  */
-static void
-snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
+static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
 }
 
@@ -384,8 +307,7 @@ snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
  * @port: port to operate on - we only have one port so we ignore this
  *
  */
-static unsigned int
-snp_get_mctrl(struct uart_port *port)
+static unsigned int snp_get_mctrl(struct uart_port *port)
 {
        return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
 }
@@ -395,8 +317,7 @@ snp_get_mctrl(struct uart_port *port)
  * @port: Port to operate on - we ignore
  *
  */
-static void
-snp_stop_rx(struct uart_port *port)
+static void snp_stop_rx(struct uart_port *port)
 {
 }
 
@@ -406,11 +327,11 @@ snp_stop_rx(struct uart_port *port)
  * @tty_stop: Set to 1 if called via uart_start
  *
  */
-static void
-snp_start_tx(struct uart_port *port, unsigned int tty_stop)
+static void snp_start_tx(struct uart_port *port, unsigned int tty_stop)
 {
        if (sal_console_port.sc_ops->sal_wakeup_transmit)
-               sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port, TRANSMIT_BUFFERED);
+               sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
+                                                            TRANSMIT_BUFFERED);
 
 }
 
@@ -420,8 +341,7 @@ snp_start_tx(struct uart_port *port, unsigned int tty_stop)
  * @break_state: Break state
  *
  */
-static void
-snp_break_ctl(struct uart_port *port, int break_state)
+static void snp_break_ctl(struct uart_port *port, int break_state)
 {
 }
 
@@ -430,8 +350,7 @@ snp_break_ctl(struct uart_port *port, int break_state)
  * @port: Port to operate on
  *
  */
-static int
-snp_startup(struct uart_port *port)
+static int snp_startup(struct uart_port *port)
 {
        return 0;
 }
@@ -454,8 +373,7 @@ snp_set_termios(struct uart_port *port, struct termios *termios,
  * @port: port to operate on
  *
  */
-static int
-snp_request_port(struct uart_port *port)
+static int snp_request_port(struct uart_port *port)
 {
        return 0;
 }
@@ -466,8 +384,7 @@ snp_request_port(struct uart_port *port)
  * @flags: flags used for port setup
  *
  */
-static void
-snp_config_port(struct uart_port *port, int flags)
+static void snp_config_port(struct uart_port *port, int flags)
 {
 }
 
@@ -505,22 +422,17 @@ static struct uart_ops sn_console_ops = {
  * itself may be broken.
  *
  */
-static int
-sn_debug_printf(const char *fmt, ...)
+static int sn_debug_printf(const char *fmt, ...)
 {
        static char printk_buf[1024];
        int printed_len;
        va_list args;
 
        va_start(args, fmt);
-       printed_len = vsnprintf(printk_buf, sizeof (printk_buf), fmt, args);
+       printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 
        if (!sal_console_port.sc_ops) {
-               if (IS_RUNNING_ON_SIMULATOR())
-                       sal_console_port.sc_ops = &sim_ops;
-               else
-                       sal_console_port.sc_ops = &poll_ops;
-
+               sal_console_port.sc_ops = &poll_ops;
                early_sn_setup();
        }
        sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len);
@@ -528,13 +440,12 @@ sn_debug_printf(const char *fmt, ...)
        va_end(args);
        return printed_len;
 }
-#endif /* DEBUG */
+#endif                         /* DEBUG */
 
 /*
  * Interrupt handling routines.
  */
 
-
 /**
  * sn_receive_chars - Grab characters, pass them to tty layer
  * @port: Port to operate on
@@ -635,8 +546,7 @@ sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs,
  * ignore them until we register with the serial core stuffs.
  *
  */
-static void
-sn_transmit_chars(struct sn_cons_port *port, int raw)
+static void sn_transmit_chars(struct sn_cons_port *port, int raw)
 {
        int xmit_count, tail, head, loops, ii;
        int result;
@@ -651,8 +561,7 @@ sn_transmit_chars(struct sn_cons_port *port, int raw)
        if (port->sc_port.info) {
                /* We're initilized, using serial core infrastructure */
                xmit = &port->sc_port.info->xmit;
-       }
-       else {
+       } else {
                /* Probably sn_sal_switch_to_asynch has been run but serial core isn't
                 * initilized yet.  Just return.  Writes are going through
                 * sn_sal_console_write (due to register_console) at this time.
@@ -704,7 +613,7 @@ sn_transmit_chars(struct sn_cons_port *port, int raw)
                uart_write_wakeup(&port->sc_port);
 
        if (uart_circ_empty(xmit))
-               snp_stop_tx(&port->sc_port, 0); /* no-op for us */
+               snp_stop_tx(&port->sc_port, 0); /* no-op for us */
 }
 
 /**
@@ -714,10 +623,9 @@ sn_transmit_chars(struct sn_cons_port *port, int raw)
  * @regs: Saved registers, used by sn_receive_chars for uart_handle_sysrq_char
  *
  */
-static irqreturn_t
-sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-       struct sn_cons_port *port = (struct sn_cons_port *) dev_id;
+       struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
        unsigned long flags;
        int status = ia64_sn_console_intr_status();
 
@@ -742,8 +650,7 @@ sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  * returns the console irq if interrupt is successfully registered, else 0
  *
  */
-static int
-sn_sal_connect_interrupt(struct sn_cons_port *port)
+static int sn_sal_connect_interrupt(struct sn_cons_port *port)
 {
        if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
                        SA_INTERRUPT | SA_SHIRQ,
@@ -764,10 +671,9 @@ sn_sal_connect_interrupt(struct sn_cons_port *port)
  * Obviously not used in interrupt mode
  *
  */
-static void
-sn_sal_timer_poll(unsigned long data)
+static void sn_sal_timer_poll(unsigned long data)
 {
-       struct sn_cons_port *port = (struct sn_cons_port *) data;
+       struct sn_cons_port *port = (struct sn_cons_port *)data;
        unsigned long flags;
 
        if (!port)
@@ -797,8 +703,7 @@ sn_sal_timer_poll(unsigned long data)
  * if we didn't already come through here via sn_sal_serial_console_init.
  *
  */
-static void __init
-sn_sal_switch_to_asynch(struct sn_cons_port *port)
+static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port)
 {
        unsigned long flags;
 
@@ -813,12 +718,8 @@ sn_sal_switch_to_asynch(struct sn_cons_port *port)
        spin_lock_irqsave(&port->sc_port.lock, flags);
 
        /* early_printk invocation may have done this for us */
-       if (!port->sc_ops) {
-               if (IS_RUNNING_ON_SIMULATOR())
-                       port->sc_ops = &sim_ops;
-               else
-                       port->sc_ops = &poll_ops;
-       }
+       if (!port->sc_ops)
+               port->sc_ops = &poll_ops;
 
        /* we can't turn on the console interrupt (as request_irq
         * calls kmalloc, which isn't set up yet), so we rely on a
@@ -827,7 +728,7 @@ sn_sal_switch_to_asynch(struct sn_cons_port *port)
         */
        init_timer(&port->sc_timer);
        port->sc_timer.function = sn_sal_timer_poll;
-       port->sc_timer.data = (unsigned long) port;
+       port->sc_timer.data = (unsigned long)port;
 
        if (IS_RUNNING_ON_SIMULATOR())
                port->sc_interrupt_timeout = 6;
@@ -854,8 +755,7 @@ sn_sal_switch_to_asynch(struct sn_cons_port *port)
  * We attempt to switch to interrupt mode here by calling
  * sn_sal_connect_interrupt.  If that works out, we enable receive interrupts.
  */
-static void __init
-sn_sal_switch_to_interrupts(struct sn_cons_port *port)
+static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
 {
        int irq;
        unsigned long flags;
@@ -893,7 +793,7 @@ static struct console sal_console = {
        .write = sn_sal_console_write,
        .device = uart_console_device,
        .setup = sn_sal_console_setup,
-       .index = -1, /* unspecified */
+       .index = -1,            /* unspecified */
        .data = &sal_console_uart,
 };
 
@@ -903,9 +803,9 @@ static struct uart_driver sal_console_uart = {
        .owner = THIS_MODULE,
        .driver_name = "sn_console",
        .dev_name = DEVICE_NAME,
-       .major = 0, /* major/minor set at registration time per USE_DYNAMIC_MINOR */
+       .major = 0,             /* major/minor set at registration time per USE_DYNAMIC_MINOR */
        .minor = 0,
-       .nr = 1,        /* one port */
+       .nr = 1,                /* one port */
        .cons = SAL_CONSOLE,
 };
 
@@ -918,8 +818,7 @@ static struct uart_driver sal_console_uart = {
  * core and try to enable interrupt driven mode.
  *
  */
-static int __init
-sn_sal_module_init(void)
+static int __init sn_sal_module_init(void)
 {
        int retval;
 
@@ -933,23 +832,24 @@ sn_sal_module_init(void)
                misc.name = DEVICE_NAME_DYNAMIC;
                retval = misc_register(&misc);
                if (retval != 0) {
-                       printk("Failed to register console device using misc_register.\n");
+                       printk
+                           ("Failed to register console device using misc_register.\n");
                        return -ENODEV;
                }
                sal_console_uart.major = MISC_MAJOR;
                sal_console_uart.minor = misc.minor;
-       }
-       else {
+       } else {
                sal_console_uart.major = DEVICE_MAJOR;
                sal_console_uart.minor = DEVICE_MINOR;
        }
 
        /* We register the driver and the port before switching to interrupts
-    * or async above so the proper uart structures are populated */
+        * or async above so the proper uart structures are populated */
 
        if (uart_register_driver(&sal_console_uart) < 0) {
-               printk("ERROR sn_sal_module_init failed uart_register_driver, line %d\n",
-                 __LINE__);
+               printk
+                   ("ERROR sn_sal_module_init failed uart_register_driver, line %d\n",
+                    __LINE__);
                return -ENODEV;
        }
 
@@ -985,8 +885,7 @@ sn_sal_module_init(void)
  * sn_sal_module_exit - When we're unloaded, remove the driver/port
  *
  */
-static void __exit
-sn_sal_module_exit(void)
+static void __exit sn_sal_module_exit(void)
 {
        del_timer_sync(&sal_console_port.sc_timer);
        uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port);
@@ -1008,7 +907,8 @@ module_exit(sn_sal_module_exit);
  *
  */
 
-static void puts_raw_fixed(int (*puts_raw) (const char *s, int len), const char *s, int count)
+static void puts_raw_fixed(int (*puts_raw) (const char *s, int len),
+                          const char *s, int count)
 {
        const char *s1;
 
@@ -1056,7 +956,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
        if (port->sc_port.info) {
 
                /* somebody really wants this output, might be an
-               * oops, kdb, panic, etc.  make sure they get it. */
+                * oops, kdb, panic, etc.  make sure they get it. */
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
                if (spin_is_locked(&port->sc_port.lock)) {
                        int lhead = port->sc_port.info->xmit.head;
@@ -1064,29 +964,39 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
                        int counter, got_lock = 0;
 
                        /*
-                        * We attempt to determine if someone has died with the
-                        * lock. We wait ~20 secs after the head and tail ptrs
-                        * stop moving and assume the lock holder is not functional
-                        * and plow ahead. If the lock is freed within the time out
-                        * period we re-get the lock and go ahead normally. We also
-                        * remember if we have plowed ahead so that we don't have
+                        * We attempt to determine if someone has died with the
+                        * lock. We wait ~20 secs after the head and tail ptrs
+                        * stop moving and assume the lock holder is not functional
+                        * and plow ahead. If the lock is freed within the time out
+                        * period we re-get the lock and go ahead normally. We also
+                        * remember if we have plowed ahead so that we don't have
                         * to wait out the time out period again - the asumption
-                        * is that we will time out again.
-                        */
+                        * is that we will time out again.
+                        */
 
                        for (counter = 0; counter < 150; mdelay(125), counter++) {
-                               if (!spin_is_locked(&port->sc_port.lock) || stole_lock) {
+                               if (!spin_is_locked(&port->sc_port.lock)
+                                   || stole_lock) {
                                        if (!stole_lock) {
-                                               spin_lock_irqsave(&port->sc_port.lock, flags);
+                                               spin_lock_irqsave(&port->
+                                                                 sc_port.lock,
+                                                                 flags);
                                                got_lock = 1;
                                        }
                                        break;
-                               }
-                               else {
+                               } else {
                                        /* still locked */
-                                       if ((lhead != port->sc_port.info->xmit.head) || (ltail != port->sc_port.info->xmit.tail)) {
-                                               lhead = port->sc_port.info->xmit.head;
-                                               ltail = port->sc_port.info->xmit.tail;
+                                       if ((lhead !=
+                                            port->sc_port.info->xmit.head)
+                                           || (ltail !=
+                                               port->sc_port.info->xmit.
+                                               tail)) {
+                                               lhead =
+                                                   port->sc_port.info->xmit.
+                                                   head;
+                                               ltail =
+                                                   port->sc_port.info->xmit.
+                                                   tail;
                                                counter = 0;
                                        }
                                }
@@ -1094,16 +1004,15 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
                        /* flush anything in the serial core xmit buffer, raw */
                        sn_transmit_chars(port, 1);
                        if (got_lock) {
-                               spin_unlock_irqrestore(&port->sc_port.lock, flags);
+                               spin_unlock_irqrestore(&port->sc_port.lock,
+                                                      flags);
                                stole_lock = 0;
-                       }
-                       else {
+                       } else {
                                /* fell thru */
                                stole_lock = 1;
                        }
                        puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-               }
-               else {
+               } else {
                        stole_lock = 0;
 #endif
                        spin_lock_irqsave(&port->sc_port.lock, flags);
@@ -1134,8 +1043,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
  * here so providing it is easier.
  *
  */
-static int __init
-sn_sal_console_setup(struct console *co, char *options)
+static int __init sn_sal_console_setup(struct console *co, char *options)
 {
        return 0;
 }
@@ -1163,7 +1071,7 @@ static struct console sal_console_early __initdata = {
        .name = "sn_sal",
        .write = sn_sal_console_write_early,
        .flags = CON_PRINTBUFFER,
-       .index  = -1,
+       .index = -1,
 };
 
 /**
@@ -1175,24 +1083,18 @@ static struct console sal_console_early __initdata = {
  * sn_sal_serial_console_init is called, this console is unregistered
  * and a new one registered.
  */
-int __init
-sn_serial_console_early_setup(void)
+int __init sn_serial_console_early_setup(void)
 {
        if (!ia64_platform_is("sn2"))
                return -1;
 
-       if (IS_RUNNING_ON_SIMULATOR())
-               sal_console_port.sc_ops = &sim_ops;
-       else
-               sal_console_port.sc_ops = &poll_ops;
-
-       early_sn_setup(); /* Find SAL entry points */
+       sal_console_port.sc_ops = &poll_ops;
+       early_sn_setup();       /* Find SAL entry points */
        register_console(&sal_console_early);
 
        return 0;
 }
 
-
 /**
  * sn_sal_serial_console_init - Early console output - set up for register
  *
@@ -1205,12 +1107,11 @@ sn_serial_console_early_setup(void)
  * it here doesn't hurt anything.
  *
  */
-static int __init
-sn_sal_serial_console_init(void)
+static int __init sn_sal_serial_console_init(void)
 {
        if (ia64_platform_is("sn2")) {
                sn_sal_switch_to_asynch(&sal_console_port);
-               DPRINTF ("sn_sal_serial_console_init : register console\n");
+               DPRINTF("sn_sal_serial_console_init : register console\n");
                register_console(&sal_console);
                unregister_console(&sal_console_early);
        }
index caaa89a..186f130 100644 (file)
  *
  */
 #include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_UART00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/serial.h>
 #include <linux/console.h>
 #include <linux/sysrq.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/sizes.h>
 
-#if defined(CONFIG_SERIAL_UART00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
 #include <asm/arch/excalibur.h>
 #define UART00_TYPE (volatile unsigned int*)
 #include <asm/arch/uart00.h>
@@ -132,9 +134,8 @@ uart00_rx_chars(struct uart_port *port, struct pt_regs *regs)
                        goto ignore_char;
 
        error_return:
-               *tty->flip.flag_buf_ptr++ = flg;
-               *tty->flip.char_buf_ptr++ = ch;
-               tty->flip.count++;
+               tty_insert_flip_char(tty, ch, flg);
+
        ignore_char:
                status = UART_GET_RSR(port);
        }
@@ -174,11 +175,7 @@ uart00_rx_chars(struct uart_port *port, struct pt_regs *regs)
                 * CHECK: does overrun affect the current character?
                 * ASSUMPTION: it does not.
                 */
-               *tty->flip.flag_buf_ptr++ = flg;
-               *tty->flip.char_buf_ptr++ = ch;
-               tty->flip.count++;
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                       goto ignore_char;
+               tty_insert_flip_char(tty, ch, flg);
                ch = 0;
                flg = TTY_OVERRUN;
        }
index 0902769..f216f6a 100644 (file)
@@ -23,7 +23,7 @@
  
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
+module_param(pc_debug, int, 0644);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 #else
 #define DEBUG(n, args...)
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.
index c06a3c1..f17e576 100644 (file)
@@ -816,6 +816,9 @@ static void speedtch_usb_disconnect(struct usb_interface *intf)
                return;
        }
 
+/*QQ need to handle disconnects on interface #2 while uploading firmware */
+/*QQ and what about interface #1? */
+
        if (instance->int_urb) {
                struct urb *int_urb = instance->int_urb;
                instance->int_urb = NULL;
index 9180dda..d1e271e 100644 (file)
@@ -111,7 +111,7 @@ static int udsl_print_packet(const unsigned char *data, int len);
 
 #define DRIVER_AUTHOR  "Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
 #define DRIVER_VERSION "1.8"
-#define DRIVER_DESC    "Alcatel SpeedTouch USB driver version " DRIVER_VERSION
+#define DRIVER_DESC    "Generic USB ATM/DSL I/O, version " DRIVER_VERSION
 
 static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS;
 static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS;
@@ -311,6 +311,15 @@ static void udsl_extract_cells(struct udsl_instance_data *instance,
 **  encode  **
 *************/
 
+static inline void udsl_fill_cell_header(unsigned char *target, struct atm_vcc *vcc)
+{
+       target[0] = vcc->vpi >> 4;
+       target[1] = (vcc->vpi << 4) | (vcc->vci >> 12);
+       target[2] = vcc->vci >> 4;
+       target[3] = vcc->vci << 4;
+       target[4] = 0xec;
+}
+
 static const unsigned char zeros[ATM_CELL_PAYLOAD];
 
 static void udsl_groom_skb(struct atm_vcc *vcc, struct sk_buff *skb)
@@ -320,11 +329,6 @@ static void udsl_groom_skb(struct atm_vcc *vcc, struct sk_buff *skb)
        u32 crc;
 
        ctrl->atm_data.vcc = vcc;
-       ctrl->cell_header[0] = vcc->vpi >> 4;
-       ctrl->cell_header[1] = (vcc->vpi << 4) | (vcc->vci >> 12);
-       ctrl->cell_header[2] = vcc->vci >> 4;
-       ctrl->cell_header[3] = vcc->vci << 4;
-       ctrl->cell_header[4] = 0xec;
 
        ctrl->num_cells = UDSL_NUM_CELLS(skb->len);
        ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD;
@@ -366,7 +370,7 @@ static unsigned int udsl_write_cells(struct udsl_instance_data *instance,
        ne = min(howmany, ctrl->num_entire);
 
        for (i = 0; i < ne; i++) {
-               memcpy(target, ctrl->cell_header, ATM_CELL_HEADER);
+               udsl_fill_cell_header(target, ctrl->atm_data.vcc);
                target += ATM_CELL_HEADER;
                memcpy(target, skb->data, ATM_CELL_PAYLOAD);
                target += ATM_CELL_PAYLOAD;
@@ -382,11 +386,7 @@ static unsigned int udsl_write_cells(struct udsl_instance_data *instance,
        if (!(ctrl->num_cells -= ne) || !(howmany -= ne))
                goto out;
 
-       if (instance->snd_padding) {
-               memset(target, 0, instance->snd_padding);
-               target += instance->snd_padding;
-       }
-       memcpy(target, ctrl->cell_header, ATM_CELL_HEADER);
+       udsl_fill_cell_header(target, ctrl->atm_data.vcc);
        target += ATM_CELL_HEADER;
        memcpy(target, skb->data, skb->len);
        target += skb->len;
@@ -400,7 +400,11 @@ static unsigned int udsl_write_cells(struct udsl_instance_data *instance,
                        goto out;
                }
 
-               memcpy(target, ctrl->cell_header, ATM_CELL_HEADER);
+               if (instance->snd_padding) {
+                       memset(target, 0, instance->snd_padding);
+                       target += instance->snd_padding;
+               }
+               udsl_fill_cell_header(target, ctrl->atm_data.vcc);
                target += ATM_CELL_HEADER;
                memset(target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
                target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
index 188e917..219763c 100644 (file)
@@ -91,7 +91,6 @@ struct udsl_control {
        unsigned int num_cells;
        unsigned int num_entire;
        unsigned int pdu_padding;
-       unsigned char cell_header[ATM_CELL_HEADER];
        unsigned char aal5_trailer[ATM_AAL5_TRAILER];
 };
 
index 3d49e9d..0561d02 100644 (file)
@@ -9,7 +9,8 @@ config USB_AUDIO
        depends on USB && SOUND
        help
          Say Y here if you want to connect USB audio equipment such as
-         speakers to your computer's USB port.
+         speakers to your computer's USB port. You only need this if you use
+         the OSS sound driver; ALSA has its own option for usb audio support.
 
          To compile this driver as a module, choose M here: the
          module will be called audio.
index cc26d95..da945b3 100644 (file)
@@ -117,6 +117,7 @@ struct union_desc {
 } __attribute__ ((packed));
 
 /* class specific descriptor types */
+#define CDC_HEADER_TYPE                        0x00
 #define CDC_CALL_MANAGEMENT_TYPE       0x01
 #define CDC_AC_MANAGEMENT_TYPE         0x02
 #define CDC_UNION_TYPE                 0x06
index 78c5ca2..bae974d 100644 (file)
 static ssize_t  show_##field (struct device *dev, char *buf)           \
 {                                                                      \
        struct usb_device *udev;                                        \
+       struct usb_host_config *actconfig;                              \
                                                                        \
        udev = to_usb_device (dev);                                     \
-       if (udev->actconfig)                                            \
+       actconfig = udev->actconfig;                                    \
+       if (actconfig)                                                  \
                return sprintf (buf, format_string,                     \
-                               udev->actconfig->desc.field * multiplier);      \
+                               actconfig->desc.field * multiplier);    \
        else                                                            \
                return 0;                                               \
 }                                                                      \
@@ -44,6 +46,28 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
 usb_actconfig_attr (bmAttributes, 1, "%2x\n")
 usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
 
+#define usb_actconfig_str(name, field)                                 \
+static ssize_t  show_##name(struct device *dev, char *buf)             \
+{                                                                      \
+       struct usb_device *udev;                                        \
+       struct usb_host_config *actconfig;                              \
+       int len;                                                        \
+                                                                       \
+       udev = to_usb_device (dev);                                     \
+       actconfig = udev->actconfig;                                    \
+       if (!actconfig)                                                 \
+               return 0;                                               \
+       len = usb_string(udev, actconfig->desc.field, buf, PAGE_SIZE);  \
+       if (len < 0)                                                    \
+               return 0;                                               \
+       buf[len] = '\n';                                                \
+       buf[len+1] = 0;                                                 \
+       return len+1;                                                   \
+}                                                                      \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+
+usb_actconfig_str (configuration, iConfiguration)
+
 /* configuration value is always present, and r/w */
 usb_actconfig_show(bConfigurationValue, 1, "%u\n");
 
@@ -55,9 +79,9 @@ set_bConfigurationValue (struct device *dev, const char *buf, size_t count)
 
        if (sscanf (buf, "%u", &config) != 1 || config > 255)
                return -EINVAL;
-       down(&udev->serialize);
+       usb_lock_device(udev);
        value = usb_set_configuration (udev, config);
-       up(&udev->serialize);
+       usb_unlock_device(udev);
        return (value < 0) ? value : count;
 }
 
@@ -198,6 +222,7 @@ void usb_create_sysfs_dev_files (struct usb_device *udev)
                device_create_file (dev, &dev_attr_product);
        if (udev->descriptor.iSerialNumber)
                device_create_file (dev, &dev_attr_serial);
+       device_create_file (dev, &dev_attr_configuration);
 }
 
 void usb_remove_sysfs_dev_files (struct usb_device *udev)
@@ -212,6 +237,7 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
                device_remove_file(dev, &dev_attr_product);
        if (udev->descriptor.iSerialNumber)
                device_remove_file(dev, &dev_attr_serial);
+       device_remove_file (dev, &dev_attr_configuration);
 }
 
 /* Interface fields */
@@ -231,7 +257,26 @@ usb_intf_attr (bNumEndpoints, "%02x\n")
 usb_intf_attr (bInterfaceClass, "%02x\n")
 usb_intf_attr (bInterfaceSubClass, "%02x\n")
 usb_intf_attr (bInterfaceProtocol, "%02x\n")
-usb_intf_attr (iInterface, "%02x\n")
+
+#define usb_intf_str(name, field)                                      \
+static ssize_t  show_##name(struct device *dev, char *buf)             \
+{                                                                      \
+       struct usb_interface *intf;                                     \
+       struct usb_device *udev;                                        \
+       int len;                                                        \
+                                                                       \
+       intf = to_usb_interface (dev);                                  \
+       udev = interface_to_usbdev (intf);                              \
+       len = usb_string(udev, intf->cur_altsetting->desc.field, buf, PAGE_SIZE);\
+       if (len < 0)                                                    \
+               return 0;                                               \
+       buf[len] = '\n';                                                \
+       buf[len+1] = 0;                                                 \
+       return len+1;                                                   \
+}                                                                      \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+
+usb_intf_str (interface, iInterface);
 
 static struct attribute *intf_attrs[] = {
        &dev_attr_bInterfaceNumber.attr,
@@ -240,7 +285,6 @@ static struct attribute *intf_attrs[] = {
        &dev_attr_bInterfaceClass.attr,
        &dev_attr_bInterfaceSubClass.attr,
        &dev_attr_bInterfaceProtocol.attr,
-       &dev_attr_iInterface.attr,
        NULL,
 };
 static struct attribute_group intf_attr_grp = {
@@ -250,9 +294,17 @@ static struct attribute_group intf_attr_grp = {
 void usb_create_sysfs_intf_files (struct usb_interface *intf)
 {
        sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
+
+       if (intf->cur_altsetting->desc.iInterface)
+               device_create_file(&intf->dev, &dev_attr_interface);
+               
 }
 
 void usb_remove_sysfs_intf_files (struct usb_interface *intf)
 {
        sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
+
+       if (intf->cur_altsetting->desc.iInterface)
+               device_remove_file(&intf->dev, &dev_attr_interface);
+
 }
index 03c639b..d5fd04d 100644 (file)
@@ -13,7 +13,7 @@ obj-$(CONFIG_USB_LH7A40X)     += lh7a40x_udc.o
 #
 g_zero-objs                    := zero.o usbstring.o config.o epautoconf.o
 g_ether-objs                   := ether.o usbstring.o config.o epautoconf.o
-g_serial-objs                  := serial.o usbstring.o epautoconf.o
+g_serial-objs                  := serial.o usbstring.o config.o epautoconf.o
 gadgetfs-objs                  := inode.o
 g_file_storage-objs            := file_storage.o usbstring.o config.o \
                                        epautoconf.o
index 61ce5b2..005db7c 100644 (file)
@@ -90,7 +90,7 @@ module_param(use_dma, uint, S_IRUGO);
 static void nuke(struct goku_ep *, int status);
 
 static inline void
-command(struct goku_udc_regs *regs, int command, unsigned epnum)
+command(struct goku_udc_regs __iomem *regs, int command, unsigned epnum)
 {
        writel(COMMAND_EP(epnum) | command, &regs->Command);
        udelay(300);
@@ -161,8 +161,8 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 
        /* ep1 and ep2 can do double buffering and/or dma */
        if (ep->num < 3) {
-               struct goku_udc_regs    *regs = ep->dev->regs;
-               u32                     tmp;
+               struct goku_udc_regs __iomem    *regs = ep->dev->regs;
+               u32                             tmp;
 
                /* double buffer except (for now) with pio in */
                tmp = ((ep->dma || !ep->is_in)
@@ -191,7 +191,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        return 0;
 }
 
-static void ep_reset(struct goku_udc_regs *regs, struct goku_ep *ep)
+static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep)
 {
        struct goku_udc         *dev = ep->dev;
 
@@ -209,16 +209,16 @@ static void ep_reset(struct goku_udc_regs *regs, struct goku_ep *ep)
                writel(dev->int_enable, &regs->int_enable);
                readl(&regs->int_enable);
                if (ep->num < 3) {
-                       struct goku_udc_regs    *regs = ep->dev->regs;
-                       u32                     tmp;
+                       struct goku_udc_regs __iomem    *r = ep->dev->regs;
+                       u32                             tmp;
 
-                       tmp = readl(&regs->EPxSingle);
+                       tmp = readl(&r->EPxSingle);
                        tmp &= ~(0x11 << ep->num);
-                       writel(tmp, &regs->EPxSingle);
+                       writel(tmp, &r->EPxSingle);
 
-                       tmp = readl(&regs->EPxBCS);
+                       tmp = readl(&r->EPxBCS);
                        tmp &= ~(0x11 << ep->num);
-                       writel(tmp, &regs->EPxBCS);
+                       writel(tmp, &r->EPxBCS);
                }
                /* reset dma in case we're still using it */
                if (ep->dma) {
@@ -237,7 +237,7 @@ static void ep_reset(struct goku_udc_regs *regs, struct goku_ep *ep)
        }
 
        ep->ep.maxpacket = MAX_FIFO_SIZE;
-       ep->desc = 0;
+       ep->desc = NULL;
        ep->stopped = 1;
        ep->irqs = 0;
        ep->dma = 0;
@@ -274,10 +274,10 @@ goku_alloc_request(struct usb_ep *_ep, int gfp_flags)
        struct goku_request     *req;
 
        if (!_ep)
-               return 0;
+               return NULL;
        req = kmalloc(sizeof *req, gfp_flags);
        if (!req)
-               return 0;
+               return NULL;
 
        memset(req, 0, sizeof *req);
        req->req.dma = DMA_ADDR_INVALID;
@@ -334,7 +334,7 @@ goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
 
        ep = container_of(_ep, struct goku_ep, ep);
        if (!_ep)
-               return 0;
+               return NULL;
        *dma = DMA_ADDR_INVALID;
 
 #if    defined(USE_KMALLOC)
@@ -413,7 +413,7 @@ done(struct goku_ep *ep, struct goku_request *req, int status)
 /*-------------------------------------------------------------------------*/
 
 static inline int
-write_packet(u32 *fifo, u8 *buf, struct goku_request *req, unsigned max)
+write_packet(u32 __iomem *fifo, u8 *buf, struct goku_request *req, unsigned max)
 {
        unsigned        length, count;
 
@@ -488,10 +488,10 @@ static int write_fifo(struct goku_ep *ep, struct goku_request *req)
 
 static int read_fifo(struct goku_ep *ep, struct goku_request *req)
 {
-       struct goku_udc_regs    *regs;
-       u32                     size, set;
-       u8                      *buf;
-       unsigned                bufferspace, is_short, dbuff;
+       struct goku_udc_regs __iomem    *regs;
+       u32                             size, set;
+       u8                              *buf;
+       unsigned                        bufferspace, is_short, dbuff;
 
        regs = ep->dev->regs;
 top:
@@ -581,7 +581,8 @@ top:
 }
 
 static inline void
-pio_irq_enable(struct goku_udc *dev, struct goku_udc_regs *regs, int epnum)
+pio_irq_enable(struct goku_udc *dev,
+               struct goku_udc_regs __iomem *regs, int epnum)
 {
        dev->int_enable |= INT_EPxDATASET (epnum);
        writel(dev->int_enable, &regs->int_enable);
@@ -589,7 +590,8 @@ pio_irq_enable(struct goku_udc *dev, struct goku_udc_regs *regs, int epnum)
 }
 
 static inline void
-pio_irq_disable(struct goku_udc *dev, struct goku_udc_regs *regs, int epnum)
+pio_irq_disable(struct goku_udc *dev,
+               struct goku_udc_regs __iomem *regs, int epnum)
 {
        dev->int_enable &= ~INT_EPxDATASET (epnum);
        writel(dev->int_enable, &regs->int_enable);
@@ -613,10 +615,10 @@ pio_advance(struct goku_ep *ep)
 // return:  0 = q running, 1 = q stopped, negative = errno
 static int start_dma(struct goku_ep *ep, struct goku_request *req)
 {
-       struct goku_udc_regs    *regs = ep->dev->regs;
-       u32                     master;
-       u32                     start = req->req.dma;
-       u32                     end = start + req->req.length - 1;
+       struct goku_udc_regs __iomem    *regs = ep->dev->regs;
+       u32                             master;
+       u32                             start = req->req.dma;
+       u32                             end = start + req->req.length - 1;
 
        master = readl(&regs->dma_master) & MST_RW_BITS;
 
@@ -668,9 +670,9 @@ static int start_dma(struct goku_ep *ep, struct goku_request *req)
 
 static void dma_advance(struct goku_udc *dev, struct goku_ep *ep)
 {
-       struct goku_request     *req;
-       struct goku_udc_regs    *regs = ep->dev->regs;
-       u32                     master;
+       struct goku_request             *req;
+       struct goku_udc_regs __iomem    *regs = ep->dev->regs;
+       u32                             master;
 
        master = readl(&regs->dma_master);
 
@@ -716,9 +718,9 @@ stop:
 
 static void abort_dma(struct goku_ep *ep, int status)
 {
-       struct goku_udc_regs    *regs = ep->dev->regs;
-       struct goku_request     *req;
-       u32                     curr, master;
+       struct goku_udc_regs __iomem    *regs = ep->dev->regs;
+       struct goku_request             *req;
+       u32                             curr, master;
 
        /* NAK future host requests, hoping the implicit delay lets the
         * dma engine finish reading (or writing) its latest packet and
@@ -848,7 +850,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
                if (unlikely(status != 0)) {
                        if (status > 0)
                                status = 0;
-                       req = 0;
+                       req = NULL;
                }
 
        } /* else pio or dma irq handler advances the queue. */
@@ -927,7 +929,7 @@ static int goku_dequeue(struct usb_ep *_ep, struct usb_request *_req)
        } else if (!list_empty(&req->queue))
                done(ep, req, -ECONNRESET);
        else
-               req = 0;
+               req = NULL;
        spin_unlock_irqrestore(&dev->lock, flags);
 
        return req ? 0 : -EOPNOTSUPP;
@@ -984,7 +986,8 @@ static int goku_set_halt(struct usb_ep *_ep, int value)
                retval = -EAGAIN;
        else if (ep->is_in && value
                        /* data in (either) packet buffer? */
-                       && (ep->dev->regs->DataSet & DATASET_AB(ep->num)))
+                       && (readl(&ep->dev->regs->DataSet)
+                                       & DATASET_AB(ep->num)))
                retval = -EAGAIN;
        else if (!value)
                goku_clear_halt(ep);
@@ -1000,9 +1003,9 @@ static int goku_set_halt(struct usb_ep *_ep, int value)
 
 static int goku_fifo_status(struct usb_ep *_ep)
 {
-       struct goku_ep          *ep;
-       struct goku_udc_regs    *regs;
-       u32                     size;
+       struct goku_ep                  *ep;
+       struct goku_udc_regs __iomem    *regs;
+       u32                             size;
 
        if (!_ep)
                return -ENODEV;
@@ -1022,9 +1025,9 @@ static int goku_fifo_status(struct usb_ep *_ep)
 
 static void goku_fifo_flush(struct usb_ep *_ep)
 {
-       struct goku_ep          *ep;
-       struct goku_udc_regs    *regs;
-       u32                     size;
+       struct goku_ep                  *ep;
+       struct goku_udc_regs __iomem    *regs;
+       u32                             size;
 
        if (!_ep)
                return;
@@ -1092,13 +1095,7 @@ static inline char *dmastr(void)
                return "(dma IN)";
 }
 
-/* if we're trying to save space, don't bother with this proc file */
-
-#if defined(CONFIG_PROC_FS) && !defined(CONFIG_EMBEDDED)
-#  define      UDC_PROC_FILE
-#endif
-
-#ifdef UDC_PROC_FILE
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
 
 static const char proc_node_name [] = "driver/udc";
 
@@ -1147,14 +1144,14 @@ static int
 udc_proc_read(char *buffer, char **start, off_t off, int count,
                int *eof, void *_dev)
 {
-       char                    *buf = buffer;
-       struct goku_udc         *dev = _dev;
-       struct goku_udc_regs    *regs = dev->regs;
-       char                    *next = buf;
-       unsigned                size = count;
-       unsigned long           flags;
-       int                     i, t, is_usb_connected;
-       u32                     tmp;
+       char                            *buf = buffer;
+       struct goku_udc                 *dev = _dev;
+       struct goku_udc_regs __iomem    *regs = dev->regs;
+       char                            *next = buf;
+       unsigned                        size = count;
+       unsigned long                   flags;
+       int                             i, t, is_usb_connected;
+       u32                             tmp;
 
        if (off != 0)
                return 0;
@@ -1312,7 +1309,7 @@ done:
        return count - size;
 }
 
-#endif /* UDC_PROC_FILE */
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
 /*-------------------------------------------------------------------------*/
 
@@ -1342,17 +1339,17 @@ static void udc_reinit (struct goku_udc *dev)
                ep->dev = dev;
                INIT_LIST_HEAD (&ep->queue);
 
-               ep_reset(0, ep);
+               ep_reset(NULL, ep);
        }
 
-       dev->ep[0].reg_mode = 0;
+       dev->ep[0].reg_mode = NULL;
        dev->ep[0].ep.maxpacket = MAX_EP0_SIZE;
        list_del_init (&dev->ep[0].ep.ep_list);
 }
 
 static void udc_reset(struct goku_udc *dev)
 {
-       struct goku_udc_regs    *regs = dev->regs;
+       struct goku_udc_regs __iomem    *regs = dev->regs;
 
        writel(0, &regs->power_detect);
        writel(0, &regs->int_enable);
@@ -1369,8 +1366,8 @@ static void udc_reset(struct goku_udc *dev)
 
 static void ep0_start(struct goku_udc *dev)
 {
-       struct goku_udc_regs    *regs = dev->regs;
-       unsigned                i;
+       struct goku_udc_regs __iomem    *regs = dev->regs;
+       unsigned                        i;
 
        VDBG(dev, "%s\n", __FUNCTION__);
 
@@ -1447,15 +1444,15 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
                return -EBUSY;
 
        /* hook up the driver */
-       driver->driver.bus = 0;
+       driver->driver.bus = NULL;
        dev->driver = driver;
        dev->gadget.dev.driver = &driver->driver;
        retval = driver->bind(&dev->gadget);
        if (retval) {
                DBG(dev, "bind to driver %s --> error %d\n",
                                driver->driver.name, retval);
-               dev->driver = 0;
-               dev->gadget.dev.driver = 0;
+               dev->driver = NULL;
+               dev->gadget.dev.driver = NULL;
                return retval;
        }
 
@@ -1477,7 +1474,7 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
        DBG (dev, "%s\n", __FUNCTION__);
 
        if (dev->gadget.speed == USB_SPEED_UNKNOWN)
-               driver = 0;
+               driver = NULL;
 
        /* disconnect gadget driver after quiesceing hw and the driver */
        udc_reset (dev);
@@ -1504,7 +1501,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
                return -EINVAL;
 
        spin_lock_irqsave(&dev->lock, flags);
-       dev->driver = 0;
+       dev->driver = NULL;
        stop_activity(dev, driver);
        spin_unlock_irqrestore(&dev->lock, flags);
 
@@ -1520,9 +1517,9 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 static void ep0_setup(struct goku_udc *dev)
 {
-       struct goku_udc_regs    *regs = dev->regs;
-       struct usb_ctrlrequest  ctrl;
-       int                     tmp;
+       struct goku_udc_regs __iomem    *regs = dev->regs;
+       struct usb_ctrlrequest          ctrl;
+       int                             tmp;
 
        /* read SETUP packet and enter DATA stage */
        ctrl.bRequestType = readl(&regs->bRequestType);
@@ -1629,11 +1626,11 @@ stall:
 
 static irqreturn_t goku_irq(int irq, void *_dev, struct pt_regs *r)
 {
-       struct goku_udc         *dev = _dev;
-       struct goku_udc_regs    *regs = dev->regs;
-       struct goku_ep          *ep;
-       u32                     stat, handled = 0;
-       unsigned                i, rescans = 5;
+       struct goku_udc                 *dev = _dev;
+       struct goku_udc_regs __iomem    *regs = dev->regs;
+       struct goku_ep                  *ep;
+       u32                             stat, handled = 0;
+       unsigned                        i, rescans = 5;
 
        spin_lock(&dev->lock);
 
@@ -1651,7 +1648,7 @@ rescan:
                        stat = 0;
                        handled = 1;
                        // FIXME have a neater way to prevent re-enumeration
-                       dev->driver = 0;
+                       dev->driver = NULL;
                        goto done;
                }
                if (stat & INT_PWRDETECT) {
@@ -1815,7 +1812,7 @@ static void goku_remove(struct pci_dev *pdev)
                usb_gadget_unregister_driver(dev->driver);
        }
 
-#ifdef UDC_PROC_FILE
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
        remove_proc_entry(proc_node_name, NULL);
 #endif
        if (dev->regs)
@@ -1831,9 +1828,9 @@ static void goku_remove(struct pci_dev *pdev)
                pci_disable_device(pdev);
        device_unregister(&dev->gadget.dev);
 
-       pci_set_drvdata(pdev, 0);
-       dev->regs = 0;
-       the_controller = 0;
+       pci_set_drvdata(pdev, NULL);
+       dev->regs = NULL;
+       the_controller = NULL;
 
        INFO(dev, "unbind\n");
 }
@@ -1844,9 +1841,9 @@ static void goku_remove(struct pci_dev *pdev)
 
 static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       struct goku_udc         *dev = 0;
+       struct goku_udc         *dev = NULL;
        unsigned long           resource, len;
-       void                    *base = 0;
+       void __iomem            *base = NULL;
        int                     retval;
        char                    buf [8], *bufp;
 
@@ -1906,7 +1903,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                retval = -EFAULT;
                goto done;
        }
-       dev->regs = (struct goku_udc_regs *) base;
+       dev->regs = (struct goku_udc_regs __iomem *) base;
 
        pci_set_drvdata(pdev, dev);
        INFO(dev, "%s\n", driver_desc);
@@ -1933,7 +1930,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                pci_set_master(pdev);
 
 
-#ifdef UDC_PROC_FILE
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
        create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
 #endif
 
@@ -1976,7 +1973,7 @@ static struct pci_driver goku_pci_driver = {
 
 static int __init init (void)
 {
-       return pci_module_init (&goku_pci_driver);
+       return pci_register_driver (&goku_pci_driver);
 }
 module_init (init);
 
index 64e8316..ea8c8e5 100644 (file)
@@ -216,9 +216,9 @@ struct goku_ep {
        struct list_head                        queue;
        const struct usb_endpoint_descriptor    *desc;
 
-       u32                                     *reg_fifo;
-       u32                                     *reg_mode;
-       u32                                     *reg_status;
+       u32 __iomem                             *reg_fifo;
+       u32 __iomem                             *reg_mode;
+       u32 __iomem                             *reg_status;
 };
 
 struct goku_request {
@@ -253,7 +253,7 @@ struct goku_udc {
 
        /* pci state used to access those endpoints */
        struct pci_dev                  *pdev;
-       struct goku_udc_regs            *regs;
+       struct goku_udc_regs __iomem    *regs;
        u32                             int_enable;
 
        /* statistics... */
index 772627e..0def9f7 100644 (file)
@@ -54,7 +54,6 @@ static const char ep0name[] = "ep0-control";
 /*
   Local definintions.
 */
-#define UDC_PROC_FILE
 
 #ifndef NO_STATES
 static char *state_names[] = {
@@ -192,7 +191,7 @@ static __inline__ void usb_clear(u32 val, u32 port)
  */
 #define is_usb_connected()             get_portc_pdr(2)
 
-#ifdef UDC_PROC_FILE
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
 
 static const char proc_node_name[] = "driver/udc";
 
@@ -248,12 +247,12 @@ udc_proc_read(char *page, char **start, off_t off, int count,
 #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 */
+#else  /* !CONFIG_USB_GADGET_DEBUG_FILES */
 
 #define create_proc_files() do {} while (0)
 #define remove_proc_files() do {} while (0)
 
-#endif                         /* UDC_PROC_FILE */
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
 /*
  *     udc_disable - disable USB device controller
index 8033c4e..fff4509 100644 (file)
@@ -495,10 +495,10 @@ set_idx_reg (struct net2280_regs __iomem *regs, u32 index, u32 value)
  * use struct net2280_dma_regs bitfields
  */
 struct net2280_dma {
-       u32             dmacount;
-       u32             dmaaddr;                /* the buffer */
-       u32             dmadesc;                /* next dma descriptor */
-       u32             _reserved;
+       __le32          dmacount;
+       __le32          dmaaddr;                /* the buffer */
+       __le32          dmadesc;                /* next dma descriptor */
+       __le32          _reserved;
 } __attribute__ ((aligned (16)));
 
 /*-------------------------------------------------------------------------*/
index e40089d..98dfa4c 100644 (file)
 
 #undef USB_TRACE
 
-/* OUT-dma seems to be behaving */
+/* bulk DMA seems to be behaving for both IN and OUT */
 #define        USE_DMA
 
 /* ISO too */
 #define        USE_ISO
 
-
 #define        DRIVER_DESC     "OMAP UDC driver"
-#define        DRIVER_VERSION  "24 August 2004"
+#define        DRIVER_VERSION  "4 October 2004"
 
 #define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
 
@@ -104,7 +103,6 @@ static unsigned fifo_mode = 0;
 module_param (fifo_mode, uint, 0);
 MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)");
 
-
 #ifdef USE_DMA
 static unsigned use_dma = 1;
 
@@ -224,18 +222,17 @@ static int omap_ep_enable(struct usb_ep *_ep,
                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.
-                        */
+       if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK)
+               /* FIXME ISO can dma, but prefers first channel */
                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))
+                       && !(ep->bEndpointAddress & USB_DIR_IN)) {
                UDC_CTRL_REG = UDC_SET_FIFO_EN;
+               ep->ackwait = 1 + ep->double_buf;
+       }
 
        spin_unlock_irqrestore(&udc->lock, flags);
        VDBG("%s enabled\n", _ep->name);
@@ -262,6 +259,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
        ep->has_dma = 0;
        UDC_CTRL_REG = UDC_SET_HALT;
        list_del_init(&ep->iso);
+       del_timer(&ep->timer);
 
        spin_unlock_irqrestore(&ep->udc->lock, flags);
 
@@ -498,17 +496,22 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
                u16     ep_stat = UDC_STAT_FLG_REG;
 
                is_last = 0;
-               if (ep_stat & FIFO_UNREADABLE)
+               if (ep_stat & FIFO_EMPTY) {
+                       if (!ep->double_buf)
+                               break;
+                       ep->fnf = 1;
+               }
+               if (ep_stat & UDC_EP_HALTED)
                        break;
 
-               if (ep_stat & (UDC_NON_ISO_FIFO_FULL|UDC_ISO_FIFO_FULL))
+               if (ep_stat & FIFO_FULL)
                        avail = ep->ep.maxpacket;
-               else 
+               else  {
                        avail = UDC_RXFSTAT_REG;
+                       ep->fnf = ep->double_buf;
+               }
                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;
@@ -526,26 +529,56 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
 
                if (!ep->bEndpointAddress)
                        break;
-               if (!ep->double_buf) {
-                       UDC_CTRL_REG = UDC_SET_FIFO_EN;
-                       if (!is_last)
-                               break;
-               }
-
-               if (is_last) {
+               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;
-               }
+               break;
        }
        return is_last;
 }
 
 /*-------------------------------------------------------------------------*/
 
+static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
+{
+       dma_addr_t      end;
+
+       /* IN-DMA needs this on fault/cancel paths, so 15xx misreports
+        * the last transfer's bytecount by more than a FIFO's worth.
+        */
+       if (cpu_is_omap15xx())
+               return 0;
+
+       end = omap_readw(OMAP_DMA_CSAC(ep->lch));
+       if (end == ep->dma_counter)
+               return 0;
+
+       end |= start & (0xffff << 16);
+       if (end < start)
+               end += 0x10000;
+       return end - start;
+}
+
+#define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
+               ? OMAP_DMA_CSAC(x) /* really: CPC */ \
+               : OMAP_DMA_CDAC(x))
+
+static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
+{
+       dma_addr_t      end;
+
+       end = omap_readw(DMA_DEST_LAST(ep->lch));
+       if (end == ep->dma_counter)
+               return 0;
+
+       end |= start & (0xffff << 16);
+       if (cpu_is_omap15xx())
+               end++;
+       if (end < start)
+               end += 0x10000;
+       return end - start;
+}
+
+
 /* 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.
@@ -555,26 +588,29 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
 {
        u16             txdma_ctrl;
        unsigned        length = req->req.length - req->req.actual;
+       const int       sync_mode = cpu_is_omap15xx()
+                               ? OMAP_DMA_SYNC_FRAME
+                               : OMAP_DMA_SYNC_ELEMENT;
 
        /* measure length in either bytes or packets */
-       if (length <= (UDC_TXN_TSC + 1)) {
+       if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1))
+                       || (cpu_is_omap15xx() && length < ep->maxpacket)) {
                txdma_ctrl = UDC_TXN_EOT | length;
                omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-                               length, 1, OMAP_DMA_SYNC_ELEMENT);
+                               length, 1, sync_mode);
        } else {
-               length = max(length / ep->maxpacket,
+               length = min(length / ep->maxpacket,
                                (unsigned) UDC_TXN_TSC + 1);
                txdma_ctrl = length;
                omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-                               ep->ep.maxpacket, length,
-                               OMAP_DMA_SYNC_ELEMENT);
+                               ep->ep.maxpacket, length, sync_mode);
                length *= ep->maxpacket;
        }
-
        omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
                OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
 
        omap_start_dma(ep->lch);
+       ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch));
        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;
@@ -592,14 +628,9 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
                                && 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;
-       }
+       } else
+               req->req.actual += dma_src_len(ep, req->req.dma
+                                                       + req->req.actual);
 
        /* tx completion */
        omap_stop_dma(ep->lch);
@@ -624,6 +655,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
                        OMAP_DMA_SYNC_ELEMENT);
        omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
                OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
+       ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch));
 
        UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
        UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
@@ -638,15 +670,13 @@ 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);
+       if (status == 0)
+               ep->dma_counter = (u16) (req->req.dma + req->req.actual);
+       count = dma_dest_len(ep, 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);
 
@@ -705,7 +735,9 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
 
        if (irq_src & UDC_RXN_CNT) {
                ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)];
-               DBG("%s, RX_CNT irq?\n", ep->ep.name);
+               ep->irqs++;
+               /* omap15xx does this unasked... */
+               VDBG("%s, RX_CNT irq?\n", ep->ep.name);
                UDC_IRQ_SRC_REG = UDC_RXN_CNT;
        }
 }
@@ -778,7 +810,8 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
 
                /* channel type P: hw synch (fifo) */
-               omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
+               if (!cpu_is_omap15xx())
+                       omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
        }
 
 just_restart:
@@ -803,6 +836,10 @@ just_restart:
                        use_ep(ep, UDC_EP_SEL);
                        (is_in ? write_fifo : read_fifo)(ep, req);
                        deselect_ep();
+                       if (!is_in) {
+                               UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                               ep->ackwait = 1 + ep->double_buf;
+                       }
                        /* IN: 6 wait states before it'll tx */
                }
        }
@@ -833,24 +870,21 @@ static void dma_channel_release(struct omap_ep *ep)
                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...) */
+                       /* clear FIFO; hosts probably won't empty it */
+                       use_ep(ep, UDC_EP_SEL);
+                       UDC_CTRL_REG = UDC_CLR_EP;
+                       deselect_ep();
+               }
                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))
+               while (UDC_RXDMA_CFG_REG & mask)
                        udelay(10);
-               omap_stop_dma(ep->lch);
                if (req)
                        finish_out_dma(ep, req, -ECONNRESET);
        }
@@ -997,6 +1031,10 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
                        if ((is_in ? write_fifo : read_fifo)(ep, req) == 1)
                                req = 0;
                        deselect_ep();
+                       if (!is_in) {
+                               UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                               ep->ackwait = 1 + ep->double_buf;
+                       }
                        /* IN: 6 wait states before it'll tx */
                }
        }
@@ -1034,7 +1072,7 @@ static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
        if (use_dma && ep->dma_channel && ep->queue.next == &req->queue) {
                int channel = ep->dma_channel;
 
-               /* releasing the dma completion cancels the request,
+               /* releasing the channel cancels the request,
                 * reclaiming the channel restarts the queue
                 */
                dma_channel_release(ep);
@@ -1104,8 +1142,10 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
                        use_ep(ep, 0);
                        UDC_CTRL_REG = UDC_RESET_EP;
                        ep->ackwait = 0;
-                       if (!(ep->bEndpointAddress & USB_DIR_IN))
+                       if (!(ep->bEndpointAddress & USB_DIR_IN)) {
                                UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                               ep->ackwait = 1 + ep->double_buf;
+                       }
                }
        }
 done:
@@ -1200,7 +1240,8 @@ static void pullup_enable(struct omap_udc *udc)
 {
        UDC_SYSCON1_REG |= UDC_PULLUP_EN;
 #ifndef CONFIG_USB_OTG
-       OTG_CTRL_REG |= OTG_BSESSVLD;
+       if (!cpu_is_omap15xx())
+               OTG_CTRL_REG |= OTG_BSESSVLD;
 #endif
        UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
 }
@@ -1208,7 +1249,8 @@ static void pullup_enable(struct omap_udc *udc)
 static void pullup_disable(struct omap_udc *udc)
 {
 #ifndef CONFIG_USB_OTG
-       OTG_CTRL_REG &= ~OTG_BSESSVLD;
+       if (!cpu_is_omap15xx())
+               OTG_CTRL_REG &= ~OTG_BSESSVLD;
 #endif
        UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
        UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
@@ -1216,7 +1258,7 @@ static void pullup_disable(struct omap_udc *udc)
 
 /*
  * Called by whatever detects VBUS sessions:  external transceiver
- * driver, or maybe GPIO0 VBUS IRQ.
+ * driver, or maybe GPIO0 VBUS IRQ.  May request 48 MHz clock.
  */
 static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
 {
@@ -1227,6 +1269,13 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
        spin_lock_irqsave(&udc->lock, flags);
        VDBG("VBUS %s\n", is_active ? "on" : "off");
        udc->vbus_active = (is_active != 0);
+       if (cpu_is_omap15xx()) {
+               /* "software" detect, ignored if !VBUS_MODE_1510 */
+               if (is_active)
+                       FUNC_MUX_CTRL_0_REG |= VBUS_CTRL_1510;
+               else
+                       FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
+       }
        if (can_pullup(udc))
                pullup_enable(udc);
        else
@@ -1340,8 +1389,15 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
        /* Clear any pending requests and then scrub any rx/tx state
         * before starting to handle the SETUP request.
         */
-       if (irq_src & UDC_SETUP)
+       if (irq_src & UDC_SETUP) {
+               u16     ack = irq_src & (UDC_EP0_TX|UDC_EP0_RX);
+
                nuke(ep0, 0);
+               if (ack) {
+                       UDC_IRQ_SRC_REG = ack;
+                       irq_src = UDC_SETUP;
+               }
+       }
 
        /* IN/OUT packets mean we're in the DATA or STATUS stage.  
         * This driver uses only uses protocol stalls (ep0 never halts),
@@ -1506,8 +1562,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                                use_ep(ep, 0);
                                UDC_CTRL_REG = UDC_RESET_EP;
                                ep->ackwait = 0;
-                               if (!(ep->bEndpointAddress & USB_DIR_IN))
+                               if (!(ep->bEndpointAddress & USB_DIR_IN)) {
                                        UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                                       ep->ackwait = 1 + ep->double_buf;
+                               }
                        }
                        VDBG("%s halt cleared by host\n", ep->name);
                        goto ep0out_status_stage;
@@ -1688,7 +1746,7 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
                }
                change &= ~UDC_SUS;
        }
-       if (change & OTG_FLAGS) {
+       if (!cpu_is_omap15xx() && (change & OTG_FLAGS)) {
                update_otg(udc);
                change &= ~OTG_FLAGS;
        }
@@ -1741,6 +1799,39 @@ omap_udc_irq(int irq, void *_udc, struct pt_regs *r)
        return status;
 }
 
+/* workaround for seemingly-lost IRQs for RX ACKs... */
+#define PIO_OUT_TIMEOUT        (jiffies + HZ/3)
+#define HALF_FULL(f)   (!((f)&(UDC_NON_ISO_FIFO_FULL|UDC_NON_ISO_FIFO_EMPTY)))
+
+static void pio_out_timer(unsigned long _ep)
+{
+       struct omap_ep  *ep = (void *) _ep;
+       unsigned long   flags;
+       u16             stat_flg;
+
+       spin_lock_irqsave(&ep->udc->lock, flags);
+       if (!list_empty(&ep->queue) && ep->ackwait) {
+               use_ep(ep, 0);
+               stat_flg = UDC_STAT_FLG_REG;
+
+               if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)
+                               || (ep->double_buf && HALF_FULL(stat_flg)))) {
+                       struct omap_req *req;
+
+                       VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg);
+                       req = container_of(ep->queue.next,
+                                       struct omap_req, queue);
+                       UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL;
+                       (void) read_fifo(ep, req);
+                       UDC_EP_NUM_REG = ep->bEndpointAddress;
+                       UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                       ep->ackwait = 1 + ep->double_buf;
+               }
+       }
+       mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
+       spin_unlock_irqrestore(&ep->udc->lock, flags);
+}
+
 static irqreturn_t
 omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
 {
@@ -1764,38 +1855,56 @@ omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
                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)) {
+               UDC_EP_NUM_REG = epnum | UDC_EP_SEL;
+               ep->fnf = 0;
+               if ((UDC_STAT_FLG_REG & UDC_ACK)) {
+                       ep->ackwait--;
+                       if (!list_empty(&ep->queue)) {
                                int stat;
                                req = container_of(ep->queue.next,
                                                struct omap_req, queue);
                                stat = read_fifo(ep, req);
-                               // FIXME double buffered PIO OUT should work
+                               if (!ep->double_buf)
+                                       ep->fnf = 1;
                        }
-                       UDC_EP_NUM_REG = epnum;
                }
+               /* min 6 clock delay before clearing EP_SEL ... */
+               epn_stat = UDC_EPN_STAT_REG;
+               epn_stat = UDC_EPN_STAT_REG;
+               UDC_EP_NUM_REG = epnum;
+
+               /* enabling fifo _after_ clearing ACK, contrary to docs,
+                * reduces lossage; timer still needed though (sigh).
+                */
+               if (ep->fnf) {
+                       UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                       ep->ackwait = 1 + ep->double_buf;
+               }
+               mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
        }
 
        /* then IN transfers */
-       if (irq_src & UDC_EPN_TX) {
+       else 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)) {
+               UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL;
+               if ((UDC_STAT_FLG_REG & UDC_ACK)) {
+                       ep->ackwait = 0;
+                       if (!list_empty(&ep->queue)) {
                                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 */
                }
+               /* min 6 clock delay before clearing EP_SEL ... */
+               epn_stat = UDC_EPN_STAT_REG;
+               epn_stat = UDC_EPN_STAT_REG;
+               UDC_EP_NUM_REG = epnum | UDC_EP_DIR;
+               /* then 6 clocks before it'd tx */
        }
 
        spin_unlock_irqrestore(&udc->lock, flags);
@@ -1937,6 +2046,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                        pullup_disable (udc);
        }
 
+       if (machine_is_omap_innovator())
+               omap_vbus_session(&udc->gadget, 1);
+
 done:
        return status;
 }
@@ -1952,6 +2064,9 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        if (!driver || driver != udc->driver)
                return -EINVAL;
 
+       if (machine_is_omap_innovator())
+               omap_vbus_session(&udc->gadget, 0);
+
        if (udc->transceiver)
                (void) otg_set_peripheral(udc->transceiver, 0);
        else
@@ -1974,7 +2089,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef CONFIG_USB_OMAP_PROC
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
 
 #include <linux/seq_file.h>
 
@@ -2000,8 +2115,16 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
 
        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,
+               "\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
+               ep->name, buf,
+               ep->double_buf ? "dbuf " : "",
+               ({char *s; switch(ep->ackwait){
+               case 0: s = ""; break;
+               case 1: s = "(ackw) "; break;
+               case 2: s = "(ackw2) "; break;
+               default: s = "(?) "; break;
+               } s;}),
+               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 " : "",
@@ -2019,10 +2142,19 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
        if (list_empty (&ep->queue))
                seq_printf(s, "\t(queue empty)\n");
        else
-               list_for_each_entry (req, &ep->queue, queue)
+               list_for_each_entry (req, &ep->queue, queue) {
+                       unsigned        length = req->req.actual;
+
+                       if (use_dma && buf[0]) {
+                               length += ((ep->bEndpointAddress & USB_DIR_IN)
+                                               ? dma_src_len : dma_dest_len)
+                                       (ep, req->req.dma + length);
+                               buf[0] = 0;
+                       }
                        seq_printf(s, "\treq %p len %d/%d buf %p\n",
-                                       &req->req, req->req.actual,
+                                       &req->req, length,
                                        req->req.length, req->req.buf);
+               }
 }
 
 static char *trx_mode(unsigned m)
@@ -2036,34 +2168,14 @@ static char *trx_mode(unsigned m)
        }
 }
 
-static int proc_udc_show(struct seq_file *s, void *_)
+static int proc_otg_show(struct seq_file *s)
 {
        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 = OTG_REV_REG;
+       seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\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 */
+               USB_TRANSCEIVER_CTRL_REG);
        tmp = OTG_SYSCON_1_REG;
        seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
                        FOURBITS "\n", tmp,
@@ -2117,6 +2229,41 @@ static int proc_udc_show(struct seq_file *s, void *_)
        seq_printf(s, "otg_outctrl %04x" "\n", tmp);
        tmp = OTG_TEST_REG;
        seq_printf(s, "otg_test    %04x" "\n", tmp);
+}
+
+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, fifo mode %d, gadget %s\n"
+               "hmc %d, transceiver %s\n",
+               tmp >> 4, tmp & 0xf,
+               fifo_mode,
+               udc->driver ? udc->driver->driver.name : "(none)",
+               HMC,
+               udc->transceiver ? udc->transceiver->label : "(none)");
+       seq_printf(s, "ULPD control %04x req %04x status %04x\n",
+               __REG16(ULPD_CLOCK_CTRL),
+               __REG16(ULPD_SOFT_REQ),
+               __REG16(ULPD_STATUS_REQ));
+
+       /* OTG controller registers */
+       if (!cpu_is_omap15xx())
+               proc_otg_show(s);
 
        tmp = UDC_SYSCON1_REG;
        seq_printf(s, "\nsyscon1     %04x" EIGHTBITS "\n", tmp,
@@ -2292,10 +2439,10 @@ omap_ep_setup(char *name, u8 addr, u8 type,
                epn_rxtx |= UDC_EPN_RX_ISO;
                dbuf = 1;
        } else {
-               /* pio-out could potentially double-buffer,
-                * as can (should!) DMA-IN
+               /* double-buffering "not supported" on 15xx,
+                * and ignored for PIO-IN on 16xx
                 */
-               if (!use_dma || (addr & USB_DIR_IN))
+               if (!use_dma || cpu_is_omap15xx())
                        dbuf = 0;
 
                switch (maxp) {
@@ -2307,6 +2454,9 @@ omap_ep_setup(char *name, u8 addr, u8 type,
                }
                if (dbuf && addr)
                        epn_rxtx |= UDC_EPN_RX_DB;
+               init_timer(&ep->timer);
+               ep->timer.function = pio_out_timer;
+               ep->timer.data = (unsigned long) ep;
        }
        if (addr)
                epn_rxtx |= UDC_EPN_RX_VALID;
@@ -2496,41 +2646,63 @@ static int __init omap_udc_probe(struct device *dev)
                return -EBUSY;
        }
 
-       INFO("OMAP UDC rev %d.%d, OTG rev %d.%d, %s receptacle\n",
+       INFO("OMAP UDC rev %d.%d%s\n",
                UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
-               OTG_REV_REG >> 4, OTG_REV_REG & 0xf,
-               config->otg ? "Mini-AB" : "B/Mini-B");
+               config->otg ? ", Mini-AB" : "");
 
        /* 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;
+       if (cpu_is_omap15xx()) {
+               hmc = HMC_1510;
+               type = "(unknown)";
+
+               if (machine_is_omap_innovator()) {
+                       /* just set up software VBUS detect, and then
+                        * later rig it so we always report VBUS.
+                        * FIXME without really sensing VBUS, we can't
+                        * know when to turn PULLUP_EN on/off; and that
+                        * means we always "need" the 48MHz clock.
+                        */
+                       u32 tmp = FUNC_MUX_CTRL_0_REG;
+
+                       FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
+                       tmp |= VBUS_MODE_1510;
+                       tmp &= ~VBUS_CTRL_1510;
+                       FUNC_MUX_CTRL_0_REG = tmp;
                }
-               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;
+       } else {
+               hmc = HMC_1610;
+               switch (hmc) {
+               case 3:
+               case 11:
+               case 16:
+               case 19:
+               case 25:
+                       xceiv = otg_get_transceiver();
+                       if (!xceiv) {
+                               DBG("external transceiver not registered!\n");
+                               if (config->otg)
+                                       goto cleanup0;
+                               type = "(unknown external)";
+                       } else
+                               type = xceiv->label;
+                       break;
+               case 0:                 /* POWERUP DEFAULT == 0 */
+               case 4:
+               case 12:
+               case 20:
+                       type = "INTEGRATED";
+                       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;
+               default:
+                       ERR("unrecognized UDC HMC mode %d\n", hmc);
+                       return -ENODEV;
+               }
        }
        INFO("hmc mode %d, transceiver %s\n", hmc, type);
 
@@ -2542,7 +2714,9 @@ static int __init omap_udc_probe(struct device *dev)
        xceiv = 0;
        // "udc" is now valid
        pullup_disable(udc);
+#if    defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
        udc->gadget.is_otg = (config->otg != 0);
+#endif
 
        /* USB general purpose IRQ:  ep0, state changes, dma, etc */
        status = request_irq(odev->resource[1].start, omap_udc_irq,
@@ -2671,14 +2845,11 @@ static struct device_driver udc_driver = {
 
 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,
+       INFO("%s, version: " DRIVER_VERSION
+#ifdef USE_ISO
+               " (iso)"
+#endif
+               "%s\n", driver_desc,
                use_dma ?  " (dma)" : "");
        return driver_register(&udc_driver);
 }
index bd5420c..c9e6854 100644 (file)
@@ -146,11 +146,14 @@ struct omap_ep {
        u8                              bmAttributes;
        unsigned                        double_buf:1;
        unsigned                        stopped:1;
-       unsigned                        ackwait:1;
+       unsigned                        fnf:1;
        unsigned                        has_dma:1;
+       u8                              ackwait;
        u8                              dma_channel;
+       u16                             dma_counter;
        int                             lch;
        struct omap_udc                 *udc;
+       struct timer_list               timer;
 };
 
 struct omap_udc {
@@ -168,7 +171,6 @@ struct omap_udc {
        unsigned                        ep0_set_config:1;
        unsigned                        ep0_reset_config:1;
        unsigned                        ep0_setup:1;
-       unsigned                        hmc:6;
 
        struct completion               *done;
 };
@@ -193,7 +195,14 @@ struct omap_udc {
 
 /*-------------------------------------------------------------------------*/
 
-// #define     HMC_1510        ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f)
+#define        MOD_CONF_CTRL_0_REG     __REG32(MOD_CONF_CTRL_0)
+#define        VBUS_W2FC_1510          (1 << 17)       /* 0 gpio0, 1 dvdd2 pin */
+
+#define        FUNC_MUX_CTRL_0_REG     __REG32(FUNC_MUX_CTRL_0)
+#define        VBUS_CTRL_1510          (1 << 19)       /* 1 connected (software) */
+#define        VBUS_MODE_1510          (1 << 18)       /* 0 hardware, 1 software */
+
+#define        HMC_1510        ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f)
 #define        HMC_1610        (OTG_SYSCON_2_REG & 0x3f)
-#define        HMC              HMC_1610
+#define        HMC             (cpu_is_omap15xx() ? HMC_1510 : HMC_1610)
 
index c6e6362..256787e 100644 (file)
@@ -1,3 +1,21 @@
+# Host-side USB depends on having a host controller
+# NOTE:  dummy_hcd is always an option, but it's ignored here ...
+# NOTE:  SL-811 option should be board-specific ...
+config USB_ARCH_HAS_HCD
+       boolean
+       default y if USB_ARCH_HAS_OHCI
+       default y if ARM                                # SL-811
+       default PCI
+
+# many non-PCI hcds implement OHCI
+config USB_ARCH_HAS_OHCI
+       boolean
+       default y if SA1111
+       default y if ARCH_OMAP
+       default y if ARCH_LH7A404
+       default y if PXA27x
+       default PCI
+
 #
 # USB Host Controller Drivers
 #
@@ -6,7 +24,7 @@ comment "USB Host Controller Drivers"
 
 config USB_EHCI_HCD
        tristate "EHCI HCD (USB 2.0) support"
-       depends on USB
+       depends on USB && PCI
        ---help---
          The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
          "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
@@ -51,8 +69,8 @@ config USB_EHCI_ROOT_HUB_TT
 
 config USB_OHCI_HCD
        tristate "OHCI HCD support"
-       depends on USB
-       select ISP1301_OMAP if MACH_OMAP_H2
+       depends on USB && USB_ARCH_HAS_OHCI
+       select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
        ---help---
          The Open Host Controller Interface (OHCI) is a standard for accessing
          USB 1.1 host controller hardware.  It does more in hardware than Intel's
@@ -68,7 +86,7 @@ config USB_OHCI_HCD
 
 config USB_UHCI_HCD
        tristate "UHCI HCD (most Intel and VIA) support"
-       depends on USB
+       depends on USB && PCI
        ---help---
          The Universal Host Controller Interface is a standard by Intel for
          accessing the USB hardware in the PC (which is also called the USB
@@ -82,14 +100,16 @@ config USB_UHCI_HCD
          To compile this driver as a module, choose M here: the
          module will be called uhci-hcd.
 
-config USB_SL811HS
-       tristate "SL811HS support"
-       depends on ARM && USB
+config USB_SL811_HCD
+       tristate "SL811HS HCD support"
+       depends on USB
+       default N
        help
-         Say Y here if you have a SL811HS USB host controller in your system.
-
-         If you do not know what this is, please say N.
+         The SL811HS is a single-port USB controller that supports either
+         host side or peripheral side roles.  Enable this option if your
+         board has this chip, and you want to use it as a host controller. 
+         If unsure, say N.
 
          To compile this driver as a module, choose M here: the
-         module will be called hc_sl811.
+         module will be called sl811-hcd.
 
index b1146b8..a574ca0 100644 (file)
@@ -6,5 +6,5 @@
 obj-$(CONFIG_USB_EHCI_HCD)     += ehci-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)     += ohci-hcd.o
 obj-$(CONFIG_USB_UHCI_HCD)     += uhci-hcd.o
-
-obj-$(CONFIG_USB_SL811HS)      += hc_sl811.o
+obj-$(CONFIG_USB_SL811_HCD)    += sl811-hcd.o
+obj-$(CONFIG_ETRAX_ARCH_V10)   += hc_crisv10.o
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
index 4e11a8e..a787c8f 100644 (file)
@@ -146,6 +146,7 @@ int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
 
        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 = "lh7a404";
        hcd->product_desc = "LH7A404 OHCI";
@@ -165,9 +166,8 @@ int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
 
  err2:
        hcd_buffer_destroy (hcd);
-       if (hcd)
-               driver->hcd_free(hcd);
  err1:
+       kfree(hcd);
        lh7a404_stop_hc(dev);
        release_mem_region(dev->resource[0].start,
                                dev->resource[0].end
@@ -191,8 +191,6 @@ int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
  */
 void usb_hcd_lh7a404_remove (struct usb_hcd *hcd, struct platform_device *dev)
 {
-       void *base;
-
        pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
 
        if (in_interrupt ())
@@ -211,9 +209,6 @@ void usb_hcd_lh7a404_remove (struct usb_hcd *hcd, struct platform_device *dev)
 
        usb_deregister_bus (&hcd->self);
 
-       base = hcd->regs;
-       hcd->driver->hcd_free (hcd);
-
        lh7a404_stop_hc(dev);
        release_mem_region(dev->resource[0].start,
                           dev->resource[0].end
@@ -229,38 +224,14 @@ ohci_lh7a404_start (struct usb_hcd *hcd)
        int             ret;
 
        ohci_dbg (ohci, "ohci_lh7a404_start, ohci:%p", ohci);
-                       
-       ohci->hcca = dma_alloc_coherent (hcd->self.controller,
-                       sizeof *ohci->hcca, &ohci->hcca_dma, 0);
-       if (!ohci->hcca)
-               return -ENOMEM;
-
-       ohci_dbg (ohci, "ohci_lh7a404_start, ohci->hcca:%p",
-                       ohci->hcca);
-
-       memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
-
-       if ((ret = ohci_mem_init (ohci)) < 0) {
-               ohci_stop (hcd);
+       if ((ret = ohci_init(ohci)) < 0)
                return ret;
-       }
-       ohci->regs = hcd->regs;
 
-       if (hc_reset (ohci) < 0) {
-               ohci_stop (hcd);
-               return -ENODEV;
-       }
-
-       if (hc_start (ohci) < 0) {
+       if ((ret = ohci_run (ohci)) < 0) {
                err ("can't start %s", ohci->hcd.self.bus_name);
                ohci_stop (hcd);
-               return -EBUSY;
+               return ret;
        }
-       create_debug_files (ohci);
-
-#ifdef DEBUG
-       ohci_dump (ohci, 1);
-#endif /*DEBUG*/
        return 0;
 }
 
@@ -289,7 +260,6 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
         * memory lifecycle (except per-request)
         */
        .hcd_alloc =            ohci_hcd_alloc,
-       .hcd_free =             ohci_hcd_free,
 
        /*
         * managing i/o requests and associated device resources
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)
+
index 0b0f80e..b541b67 100644 (file)
@@ -30,11 +30,12 @@ config USB_MICROTEK
          This driver can be compiled as a module, called microtek.
 
 config USB_HPUSBSCSI
-       tristate "HP53xx USB scanner support (EXPERIMENTAL)"
-       depends on USB && SCSI && EXPERIMENTAL
+       tristate "HP53xx USB scanner support"
+       depends on USB && SCSI
        help
          Say Y here if you want support for the HP 53xx series of scanners
-         and the Minolta Scan Dual. This driver is experimental.
+         and the Minolta Scan Dual.
          The scanner will be accessible as a SCSI device.
+         Please note that recent versions of SANE use usbfs, not this driver.
          This can be compiled as a module, called hpusbscsi.
 
index 206994d..3271deb 100644 (file)
@@ -31,6 +31,7 @@ struct mts_desc {
        struct mts_desc *prev;
 
        struct usb_device *usb_dev;
+       struct usb_interface *usb_intf;
 
        /* Endpoint addresses */
        u8 ep_out;
index a38b0db..d1ea1f0 100644 (file)
@@ -56,7 +56,7 @@ static void hid_pid_exit(struct hid_device* hid)
     struct hid_ff_pid *private = hid->ff_private;
     
     if (private->urbffout) {
-       usb_unlink_urb(private->urbffout);
+       usb_kill_urb(private->urbffout);
        usb_free_urb(private->urbffout);
     }
 }
index 4917b04..65dd5be 100644 (file)
 #define DRIVER_AUTHOR                  "Daniel Ritz <daniel.ritz@gmx.ch>"
 #define DRIVER_DESC                    "eGalax TouchKit USB HID Touchscreen Driver"
 
+static int swap_xy;
+module_param(swap_xy, bool, 0644);
+MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
+
 struct touchkit_usb {
        unsigned char *data;
        dma_addr_t data_dma;
@@ -80,6 +84,7 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs)
 {
        struct touchkit_usb *touchkit = urb->context;
        int retval;
+       int x, y;
 
        switch (urb->status) {
        case 0:
@@ -103,13 +108,19 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs)
                goto exit;
        }
 
+       if (swap_xy) {
+               y = TOUCHKIT_GET_X(touchkit->data);
+               x = TOUCHKIT_GET_Y(touchkit->data);
+       } else {
+               x = TOUCHKIT_GET_X(touchkit->data);
+               y = TOUCHKIT_GET_Y(touchkit->data);
+       }
+
        input_regs(&touchkit->input, regs);
        input_report_key(&touchkit->input, BTN_TOUCH,
                         TOUCHKIT_GET_TOUCHED(touchkit->data));
-       input_report_abs(&touchkit->input, ABS_X,
-                        TOUCHKIT_GET_X(touchkit->data));
-       input_report_abs(&touchkit->input, ABS_Y,
-                        TOUCHKIT_GET_Y(touchkit->data));
+       input_report_abs(&touchkit->input, ABS_X, x);
+       input_report_abs(&touchkit->input, ABS_Y, y);
        input_sync(&touchkit->input);
 
 exit:
@@ -141,7 +152,7 @@ static void touchkit_close(struct input_dev *input)
        struct touchkit_usb *touchkit = input->private;
 
        if (!--touchkit->open)
-               usb_unlink_urb(touchkit->irq);
+               usb_kill_urb(touchkit->irq);
 }
 
 static int touchkit_alloc_buffers(struct usb_device *udev,
@@ -276,7 +287,7 @@ static void touchkit_disconnect(struct usb_interface *intf)
        dbg("%s - touchkit is initialized, cleaning up", __FUNCTION__);
        usb_set_intfdata(intf, NULL);
        input_unregister_device(&touchkit->input);
-       usb_unlink_urb(touchkit->irq);
+       usb_kill_urb(touchkit->irq);
        usb_free_urb(touchkit->irq);
        touchkit_free_buffers(interface_to_usbdev(intf), touchkit);
        kfree(touchkit);
index 0c51b1e..1700f40 100644 (file)
@@ -196,7 +196,7 @@ static void usb_kbd_close(struct input_dev *dev)
        struct usb_kbd *kbd = dev->private;
 
        if (!--kbd->open)
-               usb_unlink_urb(kbd->irq);
+               usb_kill_urb(kbd->irq);
 }
 
 static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
@@ -343,7 +343,7 @@ static void usb_kbd_disconnect(struct usb_interface *intf)
        
        usb_set_intfdata(intf, NULL);
        if (kbd) {
-               usb_unlink_urb(kbd->irq);
+               usb_kill_urb(kbd->irq);
                input_unregister_device(&kbd->dev);
                usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
                kfree(kbd);
index 5bf2730..8c7381b 100644 (file)
@@ -118,7 +118,7 @@ static void usb_mouse_close(struct input_dev *dev)
        struct usb_mouse *mouse = dev->private;
 
        if (!--mouse->open)
-               usb_unlink_urb(mouse->irq);
+               usb_kill_urb(mouse->irq);
 }
 
 static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id)
@@ -223,7 +223,7 @@ static void usb_mouse_disconnect(struct usb_interface *intf)
        
        usb_set_intfdata(intf, NULL);
        if (mouse) {
-               usb_unlink_urb(mouse->irq);
+               usb_kill_urb(mouse->irq);
                input_unregister_device(&mouse->dev);
                usb_free_urb(mouse->irq);
                usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
index 1956eb0..c5fa87e 100644 (file)
@@ -214,7 +214,7 @@ static void xpad_close (struct input_dev *dev)
        struct usb_xpad *xpad = dev->private;
        
        if (!--xpad->open_count)
-               usb_unlink_urb(xpad->irq_in);
+               usb_kill_urb(xpad->irq_in);
 }
 
 static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -325,7 +325,7 @@ static void xpad_disconnect(struct usb_interface *intf)
        
        usb_set_intfdata(intf, NULL);
        if (xpad) {
-               usb_unlink_urb(xpad->irq_in);
+               usb_kill_urb(xpad->irq_in);
                input_unregister_device(&xpad->dev);
                usb_free_urb(xpad->irq_in);
                usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
index 62ff214..a58ff2e 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- * V4L2 driver for SN9C10[12] PC Camera Controllers                        *
+ * V4L2 driver for SN9C10x PC Camera Controllers                           *
  *                                                                         *
  * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
@@ -27,6 +27,7 @@
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
+#include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/types.h>
 #include <linux/param.h>
 #define SN9C102_URBS              2
 #define SN9C102_ISO_PACKETS       7
 #define SN9C102_ALTERNATE_SETTING 8
-#define SN9C102_CTRL_TIMEOUT      10*HZ
+#define SN9C102_URB_TIMEOUT       msecs_to_jiffies(3)
+#define SN9C102_CTRL_TIMEOUT      msecs_to_jiffies(100)
 
 /*****************************************************************************/
 
-#define SN9C102_MODULE_NAME  "V4L2 driver for SN9C10[12] PC Camera Controllers"
+#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
 #define SN9C102_MODULE_AUTHOR   "(C) 2004 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.08"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 8)
+#define SN9C102_MODULE_VERSION  "1:1.19"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 19)
 
-SN9C102_ID_TABLE;
-SN9C102_SENSOR_TABLE;
+enum sn9c102_bridge {
+       BRIDGE_SN9C101 = 0x01,
+       BRIDGE_SN9C102 = 0x02,
+       BRIDGE_SN9C103 = 0x04,
+};
+
+SN9C102_ID_TABLE
+SN9C102_SENSOR_TABLE
 
 enum sn9c102_frame_state {
        F_UNUSED,
@@ -94,7 +102,7 @@ enum sn9c102_stream_state {
 };
 
 struct sn9c102_sysfs_attr {
-       u8 reg, val, i2c_reg, i2c_val;
+       u8 reg, i2c_reg;
 };
 
 static DECLARE_MUTEX(sn9c102_sysfs_lock);
@@ -105,6 +113,7 @@ struct sn9c102_device {
 
        struct video_device* v4ldev;
 
+       enum sn9c102_bridge bridge;
        struct sn9c102_sensor* sensor;
 
        struct usb_device* usbdev;
@@ -114,11 +123,13 @@ struct sn9c102_device {
 
        struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
        struct list_head inqueue, outqueue;
-       u32 frame_count, nbuffers;
+       u32 frame_count, nbuffers, nreadbuffers;
 
        enum sn9c102_io_method io;
        enum sn9c102_stream_state stream;
 
+       struct v4l2_jpegcompression compression;
+
        struct sn9c102_sysfs_attr sysfs;
        u16 reg[32];
 
index 9f775f7..e4c44fa 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- * V4L2 driver for SN9C10[12] PC Camera Controllers                        *
+ * V4L2 driver for SN9C10x PC Camera Controllers                           *
  *                                                                         *
  * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
@@ -28,7 +28,6 @@
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/fs.h>
-#include <linux/time.h>
 #include <linux/delay.h>
 #include <linux/stddef.h>
 #include <linux/compiler.h>
@@ -53,8 +52,7 @@ MODULE_VERSION(SN9C102_MODULE_VERSION);
 MODULE_LICENSE(SN9C102_MODULE_LICENSE);
 
 static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
-static unsigned int nv;
-module_param_array(video_nr, short, nv, 0444);
+module_param_array(video_nr, short, NULL, 0444);
 MODULE_PARM_DESC(video_nr,
                  "\n<-1|n[,...]> Specify V4L2 minor mode number."
                  "\n -1 = use next available (default)"
@@ -102,17 +100,6 @@ static sn9c102_eof_header_t sn9c102_eof_header[] = {
 
 /*****************************************************************************/
 
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
-       unsigned long kva, ret;
-
-       kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
-       kva |= adr & (PAGE_SIZE-1);
-       ret = __pa(kva);
-       return ret;
-}
-
-
 static void* rvmalloc(size_t size)
 {
        void* mem;
@@ -169,15 +156,15 @@ static u32 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count)
 
        cam->nbuffers = count;
        while (cam->nbuffers > 0) {
-               if ((buff = rvmalloc(cam->nbuffers * imagesize)))
+               if ((buff = rvmalloc(cam->nbuffers * PAGE_ALIGN(imagesize))))
                        break;
                cam->nbuffers--;
        }
 
        for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].bufmem = buff + i*imagesize;
+               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
                cam->frame[i].buf.index = i;
-               cam->frame[i].buf.m.offset = i*imagesize;
+               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
                cam->frame[i].buf.length = imagesize;
                cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                cam->frame[i].buf.sequence = 0;
@@ -388,7 +375,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
        data[4] = data3;
        data[5] = data4;
        data[6] = data5;
-       data[7] = 0x10;
+       data[7] = 0x14;
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
                              0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
        if (res < 0)
@@ -400,7 +387,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
        if (err)
                DBG(3, "I2C write failed for %s image sensor", sensor->name)
 
-       PDBGG("I2C write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
+       PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
              "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
              n, data0, data1, data2, data3, data4, data5)
 
@@ -437,7 +424,8 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
 
 /*****************************************************************************/
 
-static void* sn9c102_find_sof_header(void* mem, size_t len)
+static void*
+sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
 {
        size_t soflen = sizeof(sn9c102_sof_header_t), i;
        u8 j, n = sizeof(sn9c102_sof_header) / soflen;
@@ -453,11 +441,15 @@ static void* sn9c102_find_sof_header(void* mem, size_t len)
 }
 
 
-static void* sn9c102_find_eof_header(void* mem, size_t len)
+static void*
+sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
 {
        size_t eoflen = sizeof(sn9c102_eof_header_t), i;
        unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
 
+       if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+               return NULL; /* EOF header does not exist in compressed data */
+
        for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
                for (j = 0; j < n; j++)
                        if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
@@ -522,9 +514,9 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
                */
 
 redo:
-               sof = sn9c102_find_sof_header(pos, len);
+               sof = sn9c102_find_sof_header(cam, pos, len);
                if (!sof) {
-                       eof = sn9c102_find_eof_header(pos, len);
+                       eof = sn9c102_find_eof_header(cam, pos, len);
                        if ((*f)->state == F_GRABBING) {
 end_of_frame:
                                img = len;
@@ -552,7 +544,9 @@ end_of_frame:
 
                                (*f)->buf.bytesused += img;
 
-                               if ((*f)->buf.bytesused == (*f)->buf.length) {
+                               if ((*f)->buf.bytesused == (*f)->buf.length ||
+                                   (cam->sensor->pix_format.pixelformat ==
+                                               V4L2_PIX_FMT_SN9C10X && eof)) {
                                        u32 b = (*f)->buf.bytesused;
                                        (*f)->state = F_DONE;
                                        (*f)->buf.sequence= ++cam->frame_count;
@@ -605,14 +599,20 @@ start_of_frame:
                                goto redo;
 
                } else if ((*f)->state == F_GRABBING) {
-                       eof = sn9c102_find_eof_header(pos, len);
+                       eof = sn9c102_find_eof_header(cam, pos, len);
                        if (eof && eof < sof)
                                goto end_of_frame; /* (1) */
                        else {
-                               DBG(3, "SOF before expected EOF after %lu "
-                                      "bytes of image data", 
-                                   (unsigned long)((*f)->buf.bytesused))
-                               goto start_of_frame;
+                               if (cam->sensor->pix_format.pixelformat ==
+                                   V4L2_PIX_FMT_SN9C10X) {
+                                       eof = sof-sizeof(sn9c102_sof_header_t);
+                                       goto end_of_frame;
+                               } else {
+                                       DBG(3, "SOF before expected EOF after "
+                                              "%lu bytes of image data", 
+                                         (unsigned long)((*f)->buf.bytesused))
+                                       goto start_of_frame;
+                               }
                        }
                }
        }
@@ -634,7 +634,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
        struct usb_device *udev = cam->usbdev;
        struct urb* urb;
        const unsigned int wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                               680, 800, 900, 1023};
+                                              680, 800, 900, 1023};
        const unsigned int psz = wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
        s8 i, j;
        int err = 0;
@@ -736,6 +736,29 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
        return err;
 }
 
+
+int sn9c102_stream_interrupt(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       cam->stream = STREAM_INTERRUPT;
+       err = wait_event_timeout(cam->wait_stream,
+                                (cam->stream == STREAM_OFF) ||
+                                (cam->state & DEV_DISCONNECTED),
+                                SN9C102_URB_TIMEOUT);
+       if (err) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "The camera is misconfigured. To use "
+                      "it, close and open /dev/video%d "
+                      "again.", cam->v4ldev->minor)
+               return err;
+       }
+       if (cam->state & DEV_DISCONNECTED)
+               return -ENODEV;
+
+       return 0;
+}
+
 /*****************************************************************************/
 
 static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
@@ -965,6 +988,11 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
                return -ENODEV;
        }
 
+       if (cam->sensor->slave_read_id == SN9C102_I2C_SLAVEID_UNAVAILABLE) {
+               up(&sn9c102_sysfs_lock);
+               return -ENOSYS;
+       }
+
        if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
                up(&sn9c102_sysfs_lock);
                return -EIO;
@@ -1022,15 +1050,79 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
 static ssize_t
 sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
 {
+       struct sn9c102_device* cam;
+       enum sn9c102_bridge bridge;
        ssize_t res = 0;
        u8 value;
        ssize_t count;
 
+       if (down_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               up(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       bridge = cam->bridge;
+
+       up(&sn9c102_sysfs_lock);
+
        value = sn9c102_strtou8(buf, len, &count);
-       if (!count || value > 0x0f)
+       if (!count)
                return -EINVAL;
 
-       if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
+       switch (bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               if (value > 0x0f)
+                       return -EINVAL;
+               if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
+                       res = sn9c102_store_val(cd, buf, len);
+               break;
+       case BRIDGE_SN9C103:
+               if (value > 0x7f)
+                       return -EINVAL;
+               if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
+                       res = sn9c102_store_val(cd, buf, len);
+               break;
+       }
+
+       return res;
+}
+
+
+static ssize_t
+sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
+{
+       ssize_t res = 0;
+       u8 value;
+       ssize_t count;
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count || value > 0x7f)
+               return -EINVAL;
+
+       if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
+               res = sn9c102_store_val(cd, buf, len);
+
+       return res;
+}
+
+
+static ssize_t
+sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
+{
+       ssize_t res = 0;
+       u8 value;
+       ssize_t count;
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count || value > 0x7f)
+               return -EINVAL;
+
+       if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
                res = sn9c102_store_val(cd, buf, len);
 
        return res;
@@ -1046,6 +1138,8 @@ static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
 static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
                          sn9c102_show_i2c_val, sn9c102_store_i2c_val);
 static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
+static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
+static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
 
 
 static void sn9c102_create_sysfs(struct sn9c102_device* cam)
@@ -1054,8 +1148,14 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
 
        video_device_create_file(v4ldev, &class_device_attr_reg);
        video_device_create_file(v4ldev, &class_device_attr_val);
-       video_device_create_file(v4ldev, &class_device_attr_green);
-       if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) {
+       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+               video_device_create_file(v4ldev, &class_device_attr_green);
+       else if (cam->bridge == BRIDGE_SN9C103) {
+               video_device_create_file(v4ldev, &class_device_attr_blue);
+               video_device_create_file(v4ldev, &class_device_attr_red);
+       }
+       if (cam->sensor->slave_write_id != SN9C102_I2C_SLAVEID_UNAVAILABLE ||
+           cam->sensor->slave_read_id != SN9C102_I2C_SLAVEID_UNAVAILABLE) {
                video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
                video_device_create_file(v4ldev, &class_device_attr_i2c_val);
        }
@@ -1063,6 +1163,35 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
 
 /*****************************************************************************/
 
+static int
+sn9c102_set_format(struct sn9c102_device* cam, struct v4l2_pix_format* fmt)
+{
+       int err = 0;
+
+       if (fmt->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
+       else
+               err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
+
+       return err ? -EIO : 0;
+}
+
+
+static int
+sn9c102_set_compression(struct sn9c102_device* cam,
+                        struct v4l2_jpegcompression* compression)
+{
+       int err = 0;
+
+       if (compression->quality == 0)
+               err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
+       else if (compression->quality == 1)
+               err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
+
+       return err ? -EIO : 0;
+}
+
+
 static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
 {
        u8 r = 0;
@@ -1092,21 +1221,13 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
        u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
           v_start = (u8)(rect->top - s->cropcap.bounds.top),
           h_size = (u8)(rect->width / 16),
-          v_size = (u8)(rect->height / 16),
-          ae_strx = 0x00,
-          ae_stry = 0x00,
-          ae_endx = h_size / 2,
-          ae_endy = v_size / 2;
+          v_size = (u8)(rect->height / 16);
        int err = 0;
 
        err += sn9c102_write_reg(cam, h_start, 0x12);
        err += sn9c102_write_reg(cam, v_start, 0x13);
        err += sn9c102_write_reg(cam, h_size, 0x15);
        err += sn9c102_write_reg(cam, v_size, 0x16);
-       err += sn9c102_write_reg(cam, ae_strx, 0x1c);
-       err += sn9c102_write_reg(cam, ae_stry, 0x1d);
-       err += sn9c102_write_reg(cam, ae_endx, 0x1e);
-       err += sn9c102_write_reg(cam, ae_endy, 0x1f);
        if (err)
                return -EIO;
 
@@ -1148,6 +1269,20 @@ static int sn9c102_init(struct sn9c102_device* cam)
                }
        }
 
+       if (!(cam->state & DEV_INITIALIZED))
+               cam->compression.quality =  cam->reg[0x17] & 0x01 ? 0 : 1;
+       else
+               err += sn9c102_set_compression(cam, &cam->compression);
+       err += sn9c102_set_format(cam, &s->pix_format);
+       if (err)
+               return err;
+
+       if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+               DBG(3, "Compressed video format is active, quality %d", 
+                   cam->compression.quality)
+       else
+               DBG(3, "Uncompressed video format is active")
+
        if (s->set_crop)
                if ((err = s->set_crop(cam, rect))) {
                        DBG(3, "set_crop() failed")
@@ -1163,9 +1298,12 @@ static int sn9c102_init(struct sn9c102_device* cam)
                                ctrl.value = qctrl[i].default_value;
                                err = s->set_ctrl(cam, &ctrl);
                                if (err) {
-                                       DBG(3, "Set control failed")
+                                       DBG(3, "Set %s control failed",
+                                           s->qctrl[i].name)
                                        return err;
                                }
+                               DBG(3, "Image sensor supports '%s' control",
+                                   s->qctrl[i].name)
                        }
        }
 
@@ -1174,6 +1312,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
                spin_lock_init(&cam->queue_lock);
                init_waitqueue_head(&cam->wait_frame);
                init_waitqueue_head(&cam->wait_stream);
+               cam->nreadbuffers = 2;
                memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
                memcpy(&(s->_rect), &(s->cropcap.defrect), 
                       sizeof(struct v4l2_rect));
@@ -1331,7 +1470,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
        }
 
        if (cam->io == IO_NONE) {
-               if (!sn9c102_request_buffers(cam, 2)) {
+               if (!sn9c102_request_buffers(cam, cam->nreadbuffers)) {
                        DBG(1, "read() failed, not enough memory")
                        up(&cam->fileop_sem);
                        return -ENOMEM;
@@ -1375,8 +1514,8 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 
        sn9c102_queue_unusedframes(cam);
 
-       if (count > f->buf.length)
-               count = f->buf.length;
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
 
        if (copy_to_user(buf, f->bufmem, count)) {
                up(&cam->fileop_sem);
@@ -1497,11 +1636,15 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
                return -EINVAL;
        }
 
+       /* VM_IO is eventually going to replace PageReserved altogether */
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+
        pos = (unsigned long)cam->frame[i].bufmem;
        while (size > 0) { /* size is page-aligned */
-               page = kvirt_to_pa(pos);
-               if (remap_page_range(vma, start, page, PAGE_SIZE, 
-                                    vma->vm_page_prot)) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE,
+                                   vma->vm_page_prot)) {
                        up(&cam->fileop_sem);
                        return -EAGAIN;
                }
@@ -1511,8 +1654,6 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
        }
 
        vma->vm_ops = &sn9c102_vm_ops;
-       vma->vm_flags &= ~VM_IO; /* not I/O memory */
-       vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
        vma->vm_private_data = &cam->frame[i];
 
        sn9c102_vm_open(vma);
@@ -1537,11 +1678,14 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                        .version = SN9C102_MODULE_VERSION_CODE,
                        .capabilities = V4L2_CAP_VIDEO_CAPTURE | 
                                        V4L2_CAP_READWRITE |
-                                       V4L2_CAP_STREAMING,
+                                       V4L2_CAP_STREAMING,
                };
 
                strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-               strlcpy(cap.bus_info, cam->dev.bus_id, sizeof(cap.bus_info));
+               if (usb_make_path(cam->usbdev, cap.bus_info,
+                   sizeof(cap.bus_info)) < 0)
+                       strlcpy(cap.bus_info, cam->dev.bus_id,
+                               sizeof(cap.bus_info));
 
                if (copy_to_user(arg, &cap, sizeof(cap)))
                        return -EFAULT;
@@ -1636,16 +1780,24 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
                        return -EFAULT;
 
-               if ((err = s->set_ctrl(cam, &ctrl)))
-                       return err;
-
                n = sizeof(s->qctrl) / sizeof(s->qctrl[0]);
                for (i = 0; i < n; i++)
                        if (ctrl.id == s->qctrl[i].id) {
-                               s->_qctrl[i].default_value = ctrl.value;
+                               if (ctrl.value < s->qctrl[i].minimum ||
+                                   ctrl.value > s->qctrl[i].maximum)
+                                       return -ERANGE;
+                               ctrl.value -= ctrl.value % s->qctrl[i].step;
                                break;
                        }
 
+               if ((err = s->set_ctrl(cam, &ctrl)))
+                       return err;
+
+               s->_qctrl[i].default_value = ctrl.value;
+
+               PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
+                     (unsigned long)ctrl.id, (unsigned long)ctrl.value)
+
                return 0;
        }
 
@@ -1742,22 +1894,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                } else
                        scale = 1;
 
-               if (cam->stream == STREAM_ON) {
-                       cam->stream = STREAM_INTERRUPT;
-                       err = wait_event_interruptible
-                             ( cam->wait_stream, 
-                               (cam->stream == STREAM_OFF) ||
-                               (cam->state & DEV_DISCONNECTED) );
-                       if (err) {
-                               cam->state |= DEV_MISCONFIGURED;
-                               DBG(1, "The camera is misconfigured. To use "
-                                      "it, close and open /dev/video%d "
-                                      "again.", cam->v4ldev->minor)
+               if (cam->stream == STREAM_ON)
+                       if ((err = sn9c102_stream_interrupt(cam)))
                                return err;
-                       }
-                       if (cam->state & DEV_DISCONNECTED)
-                               return -ENODEV;
-               }
 
                if (copy_to_user(arg, &crop, sizeof(crop))) {
                        cam->stream = stream;
@@ -1776,7 +1915,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                        DBG(1, "VIDIOC_S_CROP failed because of hardware "
                               "problems. To use the camera, close and open "
                               "/dev/video%d again.", cam->v4ldev->minor)
-                       return err;
+                       return -EIO;
                }
 
                s->pix_format.width = rect->width/scale;
@@ -1798,20 +1937,23 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
 
        case VIDIOC_ENUM_FMT:
        {
-               struct sn9c102_sensor* s = cam->sensor;
                struct v4l2_fmtdesc fmtd;
 
                if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
                        return -EFAULT;
 
-               if (fmtd.index != 0)
+               if (fmtd.index == 0) {
+                       strcpy(fmtd.description, "bayer rgb");
+                       fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+               } else if (fmtd.index == 1) {
+                       strcpy(fmtd.description, "compressed");
+                       fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+                       fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+               } else
                        return -EINVAL;
 
-               memset(&fmtd, 0, sizeof(fmtd));
-
                fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               strcpy(fmtd.description, "bayer rgb");
-               fmtd.pixelformat = s->pix_format.pixelformat;
+               memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
 
                if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
                        return -EFAULT;
@@ -1830,8 +1972,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                        return -EINVAL;
 
-               pfmt->bytesperline = (pfmt->width * pfmt->priv) / 8;
-               pfmt->sizeimage = pfmt->height * pfmt->bytesperline;
+               pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+                                    ? 0 : (pfmt->width * pfmt->priv) / 8;
+               pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
                pfmt->field = V4L2_FIELD_NONE;
                memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
 
@@ -1900,15 +2043,21 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                pix->width = rect.width / scale;
                pix->height = rect.height / scale;
 
-               pix->pixelformat = pfmt->pixelformat;
+               if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
+                   pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+                       pix->pixelformat = pfmt->pixelformat;
                pix->priv = pfmt->priv; /* bpp */
                pix->colorspace = pfmt->colorspace;
-               pix->bytesperline = (pix->width * pix->priv) / 8;
-               pix->sizeimage = pix->height * pix->bytesperline;
+               pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+                                   ? 0 : (pix->width * pix->priv) / 8;
+               pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
                pix->field = V4L2_FIELD_NONE;
 
-               if (cmd == VIDIOC_TRY_FMT)
+               if (cmd == VIDIOC_TRY_FMT) {
+                       if (copy_to_user(arg, &format, sizeof(format)))
+                               return -EFAULT;
                        return 0;
+               }
 
                for (i = 0; i < cam->nbuffers; i++)
                        if (cam->frame[i].vma_use_count) {
@@ -1917,22 +2066,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                                return -EINVAL;
                        }
 
-               if (cam->stream == STREAM_ON) {
-                       cam->stream = STREAM_INTERRUPT;
-                       err = wait_event_interruptible
-                             ( cam->wait_stream, 
-                               (cam->stream == STREAM_OFF) ||
-                               (cam->state & DEV_DISCONNECTED) );
-                       if (err) {
-                               cam->state |= DEV_MISCONFIGURED;
-                               DBG(1, "The camera is misconfigured. To use "
-                                      "it, close and open /dev/video%d "
-                                      "again.", cam->v4ldev->minor)
+               if (cam->stream == STREAM_ON)
+                       if ((err = sn9c102_stream_interrupt(cam)))
                                return err;
-                       }
-                       if (cam->state & DEV_DISCONNECTED)
-                               return -ENODEV;
-               }
 
                if (copy_to_user(arg, &format, sizeof(format))) {
                        cam->stream = stream;
@@ -1941,7 +2077,8 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
 
                sn9c102_release_buffers(cam);
 
-               err = sn9c102_set_crop(cam, &rect);
+               err += sn9c102_set_format(cam, pix);
+               err += sn9c102_set_crop(cam, &rect);
                if (s->set_crop)
                        err += s->set_crop(cam, &rect);
                err += sn9c102_set_scale(cam, scale);
@@ -1951,7 +2088,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                        DBG(1, "VIDIOC_S_FMT failed because of hardware "
                               "problems. To use the camera, close and open "
                               "/dev/video%d again.", cam->v4ldev->minor)
-                       return err;
+                       return -EIO;
                }
 
                memcpy(pfmt, pix, sizeof(*pix));
@@ -1970,6 +2107,47 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                return 0;
        }
 
+       case VIDIOC_G_JPEGCOMP:
+       {
+               if (copy_to_user(arg, &cam->compression,
+                                sizeof(cam->compression)))
+                       return -EFAULT;
+
+               return 0;
+       }
+
+       case VIDIOC_S_JPEGCOMP:
+       {
+               struct v4l2_jpegcompression jc;
+               const enum sn9c102_stream_state stream = cam->stream;
+               int err = 0;
+
+               if (copy_from_user(&jc, arg, sizeof(jc)))
+                       return -EFAULT;
+
+               if (jc.quality != 0 && jc.quality != 1)
+                       return -EINVAL;
+
+               if (cam->stream == STREAM_ON)
+                       if ((err = sn9c102_stream_interrupt(cam)))
+                               return err;
+
+               err += sn9c102_set_compression(cam, &jc);
+               if (err) { /* atomic, no rollback in ioctl() */
+                       cam->state |= DEV_MISCONFIGURED;
+                       DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                              "problems. To use the camera, close and open "
+                              "/dev/video%d again.", cam->v4ldev->minor)
+                       return -EIO;
+               }
+
+               cam->compression.quality = jc.quality;
+
+               cam->stream = stream;
+
+               return 0;
+       }
+
        case VIDIOC_REQBUFS:
        {
                struct v4l2_requestbuffers rb;
@@ -1996,22 +2174,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                                return -EINVAL;
                        }
 
-               if (cam->stream == STREAM_ON) {
-                       cam->stream = STREAM_INTERRUPT;
-                       err = wait_event_interruptible
-                             ( cam->wait_stream, 
-                               (cam->stream == STREAM_OFF) ||
-                               (cam->state & DEV_DISCONNECTED) );
-                       if (err) {
-                               cam->state |= DEV_MISCONFIGURED;
-                               DBG(1, "The camera is misconfigured. To use "
-                                      "it, close and open /dev/video%d "
-                                      "again.", cam->v4ldev->minor)
+               if (cam->stream == STREAM_ON)
+                       if ((err = sn9c102_stream_interrupt(cam)))
                                return err;
-                       }
-                       if (cam->state & DEV_DISCONNECTED)
-                               return -ENODEV;
-               }
 
                sn9c102_empty_framequeues(cam);
 
@@ -2161,22 +2326,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
                        return -EINVAL;
 
-               if (cam->stream == STREAM_ON) {
-                       cam->stream = STREAM_INTERRUPT;
-                       err = wait_event_interruptible
-                             ( cam->wait_stream, 
-                               (cam->stream == STREAM_OFF) ||
-                               (cam->state & DEV_DISCONNECTED) );
-                       if (err) {
-                               cam->state |= DEV_MISCONFIGURED;
-                               DBG(1, "The camera is misconfigured. To use "
-                                      "it, close and open /dev/video%d "
-                                      "again.", cam->v4ldev->minor)
+               if (cam->stream == STREAM_ON)
+                       if ((err = sn9c102_stream_interrupt(cam)))
                                return err;
-                       }
-                       if (cam->state & DEV_DISCONNECTED)
-                               return -ENODEV;
-               }
 
                sn9c102_empty_framequeues(cam);
 
@@ -2185,13 +2337,56 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
                return 0;
        }
 
+       case VIDIOC_G_PARM:
+       {
+               struct v4l2_streamparm sp;
+
+               if (copy_from_user(&sp, arg, sizeof(sp)))
+                       return -EFAULT;
+
+               if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       return -EINVAL;
+
+               sp.parm.capture.extendedmode = 0;
+               sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+               if (copy_to_user(arg, &sp, sizeof(sp)))
+                       return -EFAULT;
+
+               return 0;
+       }
+
+       case VIDIOC_S_PARM:
+       {
+               struct v4l2_streamparm sp;
+
+               if (copy_from_user(&sp, arg, sizeof(sp)))
+                       return -EFAULT;
+
+               if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       return -EINVAL;
+
+               sp.parm.capture.extendedmode = 0;
+
+               if (sp.parm.capture.readbuffers == 0)
+                       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+               if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
+                       sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
+
+               if (copy_to_user(arg, &sp, sizeof(sp)))
+                       return -EFAULT;
+
+               cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+               return 0;
+       }
+
        case VIDIOC_G_STD:
        case VIDIOC_S_STD:
        case VIDIOC_QUERYSTD:
        case VIDIOC_ENUMSTD:
        case VIDIOC_QUERYMENU:
-       case VIDIOC_G_PARM:
-       case VIDIOC_S_PARM:
                return -EINVAL;
 
        default:
@@ -2286,16 +2481,28 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
        r = sn9c102_read_reg(cam, 0x00);
        if (r < 0 || r != 0x10) {
-               DBG(1, "Sorry, this is not a SN9C10[12] based camera "
+               DBG(1, "Sorry, this is not a SN9C10x based camera "
                       "(vid/pid 0x%04X/0x%04X)",
                    sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct)
                err = -ENODEV;
                goto fail;
        }
 
-       DBG(2, "SN9C10[12] PC Camera Controller detected "
-              "(vid/pid 0x%04X/0x%04X)",
-           sn9c102_id_table[i].idVendor, sn9c102_id_table[i].idProduct)
+       cam->bridge = (sn9c102_id_table[i].idProduct & 0xffc0) == 0x6080 ?
+                     BRIDGE_SN9C103 : BRIDGE_SN9C102;
+       switch (cam->bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               DBG(2, "SN9C10[12] PC Camera Controller detected "
+                      "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
+                   sn9c102_id_table[i].idProduct)
+               break;
+       case BRIDGE_SN9C103:
+               DBG(2, "SN9C103 PC Camera Controller detected "
+                      "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
+                   sn9c102_id_table[i].idProduct)
+               break;
+       }
 
        for  (i = 0; sn9c102_sensor_table[i]; i++) {
                err = sn9c102_sensor_table[i](cam);
@@ -2318,7 +2525,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                cam->state |= DEV_MISCONFIGURED;
        }
 
-       strcpy(cam->v4ldev->name, "SN9C10[12] PC Camera");
+       strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
        cam->v4ldev->owner = THIS_MODULE;
        cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
        cam->v4ldev->hardware = VID_HARDWARE_SN9C102;
index a302a48..54942d6 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- * Driver for PAS106B image sensor connected to the SN9C10[12] PC Camera   *
+ * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera     *
  * Controllers                                                             *
  *                                                                         *
  * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>       *
@@ -38,14 +38,9 @@ static int pas106b_init(struct sn9c102_device* cam)
        err += sn9c102_write_reg(cam, 0x09, 0x18);
 
        err += sn9c102_i2c_write(cam, 0x02, 0x0c);
-       err += sn9c102_i2c_write(cam, 0x03, 0x12);
-       err += sn9c102_i2c_write(cam, 0x04, 0x05);
        err += sn9c102_i2c_write(cam, 0x05, 0x5a);
        err += sn9c102_i2c_write(cam, 0x06, 0x88);
        err += sn9c102_i2c_write(cam, 0x07, 0x80);
-       err += sn9c102_i2c_write(cam, 0x08, 0x01);
-       err += sn9c102_i2c_write(cam, 0x0a, 0x01);
-       err += sn9c102_i2c_write(cam, 0x0b, 0x00);
        err += sn9c102_i2c_write(cam, 0x10, 0x06);
        err += sn9c102_i2c_write(cam, 0x11, 0x06);
        err += sn9c102_i2c_write(cam, 0x12, 0x00);
@@ -62,6 +57,15 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam,
                             struct v4l2_control* ctrl)
 {
        switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = sn9c102_i2c_read(cam, 0x03),
+                           r2 = sn9c102_i2c_read(cam, 0x04);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 4) | (r2 & 0x0f);
+               }
+               return 0;
        case V4L2_CID_RED_BALANCE:
                if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
                        return -EIO;
@@ -77,16 +81,26 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam,
                        return -EIO;
                ctrl->value &= 0x1f;
                return 0;
-       case V4L2_CID_BRIGHTNESS:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
        case V4L2_CID_CONTRAST:
                if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
                        return -EIO;
                ctrl->value &= 0x07;
                return 0;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
+                       return -EIO;
+               ctrl->value = (ctrl->value & 0x1f) << 1;
+               return 0;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
+                       return -EIO;
+               ctrl->value &= 0xf8;
+               return 0;
+       case SN9C102_V4L2_CID_DAC_SIGN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x01;
+               return 0;
        default:
                return -EINVAL;
        }
@@ -99,27 +113,42 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
        int err = 0;
 
        switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
+               err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
+               break;
        case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value & 0x1f);
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
                break;
        case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x1f);
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
                break;
        case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f);
-               break;
-       case V4L2_CID_BRIGHTNESS:
-               err += sn9c102_i2c_write(cam, 0x0d, 0x1f-(ctrl->value & 0x1f));
+               err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
                break;
        case V4L2_CID_CONTRAST:
-               err += sn9c102_i2c_write(cam, 0x0f, ctrl->value & 0x03);
+               err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
+               err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
+               break;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
+               break;
+       case SN9C102_V4L2_CID_DAC_SIGN:
+               {
+                       int r;
+                       err += (r = sn9c102_i2c_read(cam, 0x07)) < 0 ? r : 0;
+                       err += sn9c102_i2c_write(cam, 0x07, r | ctrl->value);
+               }
                break;
        default:
                return -EINVAL;
        }
        err += sn9c102_i2c_write(cam, 0x13, 0x01);
 
-       return err;
+       return err ? -EIO : 0;
 }
 
 
@@ -147,6 +176,36 @@ static struct sn9c102_sensor pas106b = {
        .slave_write_id = 0x40,
        .init = &pas106b_init,
        .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x125,
+                       .maximum = 0xfff,
+                       .step = 0x01,
+                       .default_value = 0x140,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0d,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_CONTRAST,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "contrast",
+                       .minimum = 0x00,
+                       .maximum = 0x07,
+                       .step = 0x01,
+                       .default_value = 0x00, /* 0x00~0x03 have same effect */
+                       .flags = 0,
+               },
                {
                        .id = V4L2_CID_RED_BALANCE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
@@ -168,33 +227,33 @@ static struct sn9c102_sensor pas106b = {
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_GAIN,
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
+                       .name = "green balance",
                        .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0d,
+                       .maximum = 0x3e,
+                       .step = 0x02,
+                       .default_value = 0x02,
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_BRIGHTNESS,
+                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "brightness",
+                       .name = "DAC magnitude",
                        .minimum = 0x00,
                        .maximum = 0x1f,
                        .step = 0x01,
-                       .default_value = 0x1f,
+                       .default_value = 0x01,
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_CONTRAST,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "contrast",
+                       .id = SN9C102_V4L2_CID_DAC_SIGN,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "DAC sign",
                        .minimum = 0x00,
-                       .maximum = 0x07,
+                       .maximum = 0x01,
                        .step = 0x01,
-                       .default_value = 0x00, /* 0x00~0x03 have same effect */
+                       .default_value = 0x00,
                        .flags = 0,
                },
        },
index 26944ea..3e2fd5a 100644 (file)
@@ -1,11 +1,14 @@
 /***************************************************************************
- * Driver for PAS202BCB image sensor connected to the SN9C10[12] PC Camera *
+ * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera   *
  * Controllers                                                             *
  *                                                                         *
  * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio                  *
  *                       <medaglia@undl.org.br>                            *
  *                       http://cadu.homelinux.com:8080/                   *
  *                                                                         *
+ * DAC Magnitude, DAC sign, exposure and green gain controls added by      *
+ * Luca Risolia <luca.risolia@studio.unibo.it>                             *
+ *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
  * the Free Software Foundation; either version 2 of the License, or       *
@@ -36,18 +39,15 @@ static int pas202bcb_init(struct sn9c102_device* cam)
        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, 0x30, 0x19);
        err += sn9c102_write_reg(cam, 0x09, 0x18);
 
-       err += sn9c102_i2c_write(cam, 0x02, 0x0c);
+       err += sn9c102_i2c_write(cam, 0x02, 0x14);
        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, 0x10, 0x08);
        err += sn9c102_i2c_write(cam, 0x13, 0x63);
        err += sn9c102_i2c_write(cam, 0x15, 0x70);
        err += sn9c102_i2c_write(cam, 0x11, 0x01);
@@ -62,6 +62,15 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
                               struct v4l2_control* ctrl)
 {
        switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = sn9c102_i2c_read(cam, 0x04),
+                           r2 = sn9c102_i2c_read(cam, 0x05);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
+               }
+               return 0;
        case V4L2_CID_RED_BALANCE:
                if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
                        return -EIO;
@@ -77,11 +86,20 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
                        return -EIO;
                ctrl->value &= 0x1f;
                return 0;
-       case V4L2_CID_BRIGHTNESS:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x06)) < 0)
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
                        return -EIO;
                ctrl->value &= 0x0f;
                return 0;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+                       return -EIO;
+               return 0;
+       case SN9C102_V4L2_CID_DAC_SIGN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0b)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x01;
+               return 0;
        default:
                return -EINVAL;
        }
@@ -94,24 +112,38 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
        int err = 0;
 
        switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
+               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+               break;
        case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x0f);
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
                break;
        case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x07, ctrl->value & 0x0f);
+               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
                break;
        case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f);
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
                break;
-       case V4L2_CID_BRIGHTNESS:
-               err += sn9c102_i2c_write(cam, 0x06, 0x0f-(ctrl->value & 0x0f));
+       case SN9C102_V4L2_CID_DAC_SIGN:
+               {
+                       int r;
+                       err += (r = sn9c102_i2c_read(cam, 0x0b)) < 0 ? r : 0;
+                       err += sn9c102_i2c_write(cam, 0x0b, r | ctrl->value);
+               }
                break;
        default:
                return -EINVAL;
        }
        err += sn9c102_i2c_write(cam, 0x11, 0x01);
 
-       return err;
+       return err ? -EIO : 0;
 }
 
 
@@ -140,6 +172,26 @@ static struct sn9c102_sensor pas202bcb = {
        .slave_write_id = 0x40,
        .init = &pas202bcb_init,
        .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x01e5,
+                       .maximum = 0x3fff,
+                       .step = 0x01,
+                       .default_value = 0x01e5,
+                       .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_RED_BALANCE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
@@ -161,23 +213,33 @@ static struct sn9c102_sensor pas202bcb = {
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_GAIN,
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
+                       .name = "green balance",
                        .minimum = 0x00,
-                       .maximum = 0x1f,
+                       .maximum = 0x0f,
                        .step = 0x01,
-                       .default_value = 0x0c,
+                       .default_value = 0x00,
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_BRIGHTNESS,
+                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "brightness",
+                       .name = "DAC magnitude",
                        .minimum = 0x00,
-                       .maximum = 0x0f,
+                       .maximum = 0xff,
                        .step = 0x01,
-                       .default_value = 0x0f,
+                       .default_value = 0x04,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_DAC_SIGN,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "DAC sign",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x01,
                        .flags = 0,
                },
        },
@@ -217,7 +279,7 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
         *  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, 0x40, 0x01); /* sensor power on */
        err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
        if (err)
                return -EIO;
index 3e7e4a2..ebafc28 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- * API for image sensors connected to the SN9C10[12] PC Camera Controllers *
+ * API for image sensors connected to the SN9C10x PC Camera Controllers    *
  *                                                                         *
  * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
@@ -89,17 +89,44 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
 /* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/
 #define SN9C102_ID_TABLE                                                      \
 static const struct usb_device_id sn9c102_id_table[] = {                      \
-       { USB_DEVICE(0xc45, 0x6001), }, /* TAS5110C1B */                      \
-       { USB_DEVICE(0xc45, 0x6005), }, /* TAS5110C1B */                      \
-       { USB_DEVICE(0xc45, 0x6009), }, /* PAS106B */                         \
-       { USB_DEVICE(0xc45, 0x600d), }, /* PAS106B */                         \
-       { USB_DEVICE(0xc45, 0x6024), },                                       \
-       { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */       \
-       { USB_DEVICE(0xc45, 0x6028), }, /* PAS202BCB */                       \
-       { USB_DEVICE(0xc45, 0x6029), }, /* PAS106B */                         \
-       { USB_DEVICE(0xc45, 0x602a), }, /* HV7131[D|E1] */                    \
-       { USB_DEVICE(0xc45, 0x602c), }, /* OV7620 */                          \
-       { USB_DEVICE(0xc45, 0x6030), }, /* MI03 */                            \
+       { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
+       { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
+       { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x6024), },                                      \
+       { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */      \
+       { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */                      \
+       { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131[D|E1] */                   \
+       { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */                        \
+       { USB_DEVICE(0x0c45, 0x602c), }, /* OV7620 */                         \
+       { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */                          \
+       { USB_DEVICE(0x0c45, 0x6080), },                                      \
+       { USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */              \
+       { USB_DEVICE(0x0c45, 0x6083), }, /* HV7131[D|E1] */                   \
+       { USB_DEVICE(0x0c45, 0x6088), },                                      \
+       { USB_DEVICE(0x0c45, 0x608a), },                                      \
+       { USB_DEVICE(0x0c45, 0x608b), },                                      \
+       { USB_DEVICE(0x0c45, 0x608c), }, /* HV7131x */                        \
+       { USB_DEVICE(0x0c45, 0x608e), }, /* CIS-VF10 */                       \
+       { USB_DEVICE(0x0c45, 0x608f), }, /* OV7630 */                         \
+       { USB_DEVICE(0x0c45, 0x60a0), },                                      \
+       { USB_DEVICE(0x0c45, 0x60a2), },                                      \
+       { USB_DEVICE(0x0c45, 0x60a3), },                                      \
+       { USB_DEVICE(0x0c45, 0x60a8), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x60aa), }, /* TAS5130D1B */                     \
+       { USB_DEVICE(0x0c45, 0x60ab), }, /* TAS5110C1B */                     \
+       { USB_DEVICE(0x0c45, 0x60ac), },                                      \
+       { USB_DEVICE(0x0c45, 0x60ae), },                                      \
+       { USB_DEVICE(0x0c45, 0x60af), }, /* PAS202BCB */                      \
+       { USB_DEVICE(0x0c45, 0x60b0), },                                      \
+       { USB_DEVICE(0x0c45, 0x60b2), },                                      \
+       { USB_DEVICE(0x0c45, 0x60b3), },                                      \
+       { USB_DEVICE(0x0c45, 0x60b8), },                                      \
+       { USB_DEVICE(0x0c45, 0x60ba), },                                      \
+       { USB_DEVICE(0x0c45, 0x60bb), },                                      \
+       { USB_DEVICE(0x0c45, 0x60bc), },                                      \
+       { USB_DEVICE(0x0c45, 0x60be), },                                      \
        { }                                                                   \
 };
 
@@ -159,6 +186,9 @@ enum sn9c102_i2c_interface {
        SN9C102_I2C_3WIRES,
 };
 
+#define SN9C102_I2C_SLAVEID_FICTITIOUS 0xff
+#define SN9C102_I2C_SLAVEID_UNAVAILABLE 0x00
+
 struct sn9c102_sensor {
        char name[32], /* sensor name */
             maintainer[64]; /* name of the mantainer <email> */
@@ -173,9 +203,7 @@ struct sn9c102_sensor {
 
        /*
           These identifiers must be provided if the image sensor implements
-          the standard I2C protocol. TASC sensors don't, although they have a
-          serial interface: so this is a case where the "raw" I2C version
-          could be helpful.
+          the standard I2C protocol.
        */
        u8 slave_read_id, slave_write_id; /* reg. 0x09 */
 
@@ -214,7 +242,8 @@ struct sn9c102_sensor {
           the list above. The returned value must follow the V4L2
           specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER
           are not supported by this driver, so do not implement them. Also,
-          passed values are NOT checked to see if they are out of bounds.
+          you don't have to check whether the passed values are out of bounds,
+          given that this is done by the core module.
        */
 
        struct v4l2_cropcap cropcap;
@@ -263,21 +292,25 @@ struct sn9c102_sensor {
           NOTE: in case, you must program the SN9C10X chip to get rid of 
                 blank pixels or blank lines at the _start_ of each line or
                 frame after each HSYNC or VSYNC, so that the image starts with
-                real RGB data (see regs 0x12,0x13) (having set H_SIZE and,
+                real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
                 V_SIZE you don't have to care about blank pixels or blank
                 lines at the end of each line or frame).
        */
 
        struct v4l2_pix_format pix_format;
        /*
-          What you have to define here are: initial 'width' and 'height' of
-          the target rectangle, the bayer 'pixelformat' and 'priv' which we'll
-          be used to indicate the number of bits per pixel, 8 or 9. 
-          Nothing more.
+          What you have to define here are: 1) initial 'width' and 'height' of
+          the target rectangle 2) the initial 'pixelformat', which can be
+          either V4L2_PIX_FMT_SN9C10X (for compressed video) or
+          V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
+          number of bits per pixel for uncompressed video, 8 or 9 (despite the
+          current value of 'pixelformat').
           NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
                   of cropcap.defrect.width and cropcap.defrect.height. I
                   suggest 1/1.
-          NOTE 2: as said above, you have to program the SN9C10X chip to get
+          NOTE 2: The initial compression quality is defined by the first bit
+                  of reg 0x17 during the initialization of the image sensor.
+          NOTE 3: as said above, you have to program the SN9C10X chip to get
                   rid of any blank pixels, so that the output of the sensor
                   matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
        */
@@ -304,4 +337,11 @@ struct sn9c102_sensor {
        struct v4l2_rect _rect;
 };
 
+/*****************************************************************************/
+
+/* Private ioctl's for control settings supported by some image sensors */
+#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
+#define SN9C102_V4L2_CID_DAC_SIGN V4L2_CID_PRIVATE_BASE + 1
+#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 2
+
 #endif /* _SN9C102_SENSOR_H_ */
index 68e1b2e..03153ca 100644 (file)
@@ -1,6 +1,6 @@
 /***************************************************************************
- * Driver for TAS5110C1B image sensor connected to the SN9C10[12] PC       *
- * Camera Controllers                                                      *
+ * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera  *
+ * Controllers                                                             *
  *                                                                         *
  * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
@@ -24,6 +24,8 @@
 
 static struct sn9c102_sensor tas5110c1b;
 
+static struct v4l2_control tas5110c1b_gain;
+
 
 static int tas5110c1b_init(struct sn9c102_device* cam)
 {
@@ -38,25 +40,42 @@ static int tas5110c1b_init(struct sn9c102_device* cam)
        err += sn9c102_write_reg(cam, 0x06, 0x18);
        err += sn9c102_write_reg(cam, 0xfb, 0x19);
 
-       err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x00, 0xc0,
-                                        0x80, 0, 0);
+       err += sn9c102_i2c_write(cam, 0xc0, 0x80);
 
        return err;
 }
 
 
+static int tas5110c1b_get_ctrl(struct sn9c102_device* cam, 
+                               struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               ctrl->value = tas5110c1b_gain.value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
 static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, 
                                const struct v4l2_control* ctrl)
 {
+       int err = 0;
+
        switch (ctrl->id) {
        case V4L2_CID_GAIN:
-               return sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11,
-                                                0x02, 0x20,
-                                                0xff - (ctrl->value & 0xff),
-                                                0, 0);
+               if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value)))
+                       tas5110c1b_gain.value = ctrl->value;
+               break;
        default:
                return -EINVAL;
        }
+
+       return err ? -EIO : 0;
 }
 
 
@@ -85,6 +104,8 @@ static struct sn9c102_sensor tas5110c1b = {
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
        .frequency = SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_3WIRES,
+       .slave_read_id = SN9C102_I2C_SLAVEID_UNAVAILABLE,
+       .slave_write_id = SN9C102_I2C_SLAVEID_FICTITIOUS,
        .init = &tas5110c1b_init,
        .qctrl = {
                {
@@ -92,9 +113,9 @@ static struct sn9c102_sensor tas5110c1b = {
                        .type = V4L2_CTRL_TYPE_INTEGER,
                        .name = "global gain",
                        .minimum = 0x00,
-                       .maximum = 0xff,
+                       .maximum = 0xf6,
                        .step = 0x01,
-                       .default_value = 0x48,
+                       .default_value = 0x40,
                        .flags = 0,
                },
        },
@@ -113,6 +134,7 @@ static struct sn9c102_sensor tas5110c1b = {
                        .height = 288,
                },
        },
+       .get_ctrl = &tas5110c1b_get_ctrl,
        .set_crop = &tas5110c1b_set_crop,
        .pix_format = {
                .width = 352,
@@ -128,9 +150,10 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
        /* This sensor has no identifiers, so let's attach it anyway */
        sn9c102_attach_sensor(cam, &tas5110c1b);
 
-       /* At the moment, sensor detection is based on USB pid/vid */
+       /* Sensor detection is based on USB pid/vid */
        if (tas5110c1b.usbdev->descriptor.idProduct != 0x6001 &&
-           tas5110c1b.usbdev->descriptor.idProduct != 0x6005)
+           tas5110c1b.usbdev->descriptor.idProduct != 0x6005 &&
+           tas5110c1b.usbdev->descriptor.idProduct != 0x60ab)
                return -ENODEV;
 
        return 0;
index 0bab194..36b00d1 100644 (file)
@@ -1,6 +1,6 @@
 /***************************************************************************
- * Driver for TAS5130D1B image sensor connected to the SN9C10[12] PC       *
- * Camera Controllers                                                      *
+ * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera  *
+ * Controllers                                                             *
  *                                                                         *
  * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
@@ -24,6 +24,8 @@
 
 static struct sn9c102_sensor tas5130d1b;
 
+static struct v4l2_control tas5130d1b_gain, tas5130d1b_exposure;
+
 
 static int tas5130d1b_init(struct sn9c102_device* cam)
 {
@@ -38,25 +40,47 @@ static int tas5130d1b_init(struct sn9c102_device* cam)
        err += sn9c102_write_reg(cam, 0x60, 0x17);
        err += sn9c102_write_reg(cam, 0x07, 0x18);
 
-       err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40,
-                                        0x47, 0, 0);
-
        return err;
 }
 
 
+static int tas5130d1b_get_ctrl(struct sn9c102_device* cam, 
+                               struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               ctrl->value = tas5130d1b_gain.value;
+               break;
+       case V4L2_CID_EXPOSURE:
+               ctrl->value = tas5130d1b_exposure.value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
 static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, 
                                const struct v4l2_control* ctrl)
 {
+       int err = 0;
+
        switch (ctrl->id) {
        case V4L2_CID_GAIN:
-               return sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11,
-                                                0x02, 0x20,
-                                                0xff - (ctrl->value & 0xff),
-                                                0, 0);
+               if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value)))
+                       tas5130d1b_gain.value = ctrl->value;
+               break;
+       case V4L2_CID_EXPOSURE:
+               if (!(err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value)))
+                       tas5130d1b_exposure.value = ctrl->value;
+               break;
        default:
                return -EINVAL;
        }
+
+       return err ? -EIO : 0;
 }
 
 
@@ -72,8 +96,8 @@ static int tas5130d1b_set_crop(struct sn9c102_device* cam,
        err += sn9c102_write_reg(cam, v_start, 0x13);
 
        /* Do NOT change! */
-       err += sn9c102_write_reg(cam, 0x1d, 0x1a);
-       err += sn9c102_write_reg(cam, 0x10, 0x1b);
+       err += sn9c102_write_reg(cam, 0x1f, 0x1a);
+       err += sn9c102_write_reg(cam, 0x1a, 0x1b);
        err += sn9c102_write_reg(cam, 0xf3, 0x19);
 
        return err;
@@ -85,6 +109,8 @@ static struct sn9c102_sensor tas5130d1b = {
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
        .frequency = SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_3WIRES,
+       .slave_read_id = SN9C102_I2C_SLAVEID_UNAVAILABLE,
+       .slave_write_id = SN9C102_I2C_SLAVEID_FICTITIOUS,
        .init = &tas5130d1b_init,
        .qctrl = {
                {
@@ -92,12 +118,23 @@ static struct sn9c102_sensor tas5130d1b = {
                        .type = V4L2_CTRL_TYPE_INTEGER,
                        .name = "global gain",
                        .minimum = 0x00,
-                       .maximum = 0xff,
+                       .maximum = 0xf6,
+                       .step = 0x02,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x00,
+                       .maximum = 0x47,
                        .step = 0x01,
                        .default_value = 0x00,
                        .flags = 0,
                },
        },
+       .get_ctrl = &tas5130d1b_get_ctrl,
        .set_ctrl = &tas5130d1b_set_ctrl,
        .cropcap = {
                .bounds = {
@@ -128,8 +165,9 @@ int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
        /* This sensor has no identifiers, so let's attach it anyway */
        sn9c102_attach_sensor(cam, &tas5130d1b);
 
-       /* At the moment, sensor detection is based on USB pid/vid */
-       if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025)
+       /* Sensor detection is based on USB pid/vid */
+       if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025 &&
+           tas5130d1b.usbdev->descriptor.idProduct != 0x60aa)
                return -ENODEV;
 
        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");
index e90a334..6a6e3de 100644 (file)
@@ -170,13 +170,11 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
                        if (result == -ETIMEDOUT)
                                retries--;
                        else if (result < 0) {
-                               err("Error executing ioctrl. code = %d",
-                                    le32_to_cpu(result));
+                               err("Error executing ioctrl. code = %d", result);
                                retries = 0;
                        } else {
-                               dbg("Executed ioctl. Result = %d (data=%04x)",
-                                    le32_to_cpu(result),
-                                    le32_to_cpu(*((long *) buffer)));
+                               dbg("Executed ioctl. Result = %d (data=%02x)",
+                                    result, buffer[0]);
                                if (copy_to_user(rio_cmd.buffer, buffer,
                                                 rio_cmd.length)) {
                                        free_page((unsigned long) buffer);
@@ -239,12 +237,10 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
                        if (result == -ETIMEDOUT)
                                retries--;
                        else if (result < 0) {
-                               err("Error executing ioctrl. code = %d",
-                                    le32_to_cpu(result));
+                               err("Error executing ioctrl. code = %d", result);
                                retries = 0;
                        } else {
-                               dbg("Executed ioctl. Result = %d",
-                                      le32_to_cpu(result));
+                               dbg("Executed ioctl. Result = %d", result);
                                retries = 0;
 
                        }
index 627a372..0c90cb2 100644 (file)
  */
 #define MAXTIGL                16
 
-/*
- * Max. packetsize for IN and OUT pipes
- */
-#define BULK_RCV_MAX   32
-#define BULK_SND_MAX   32
-
 /*
  * The driver context...
  */
@@ -42,6 +36,8 @@ typedef struct
        driver_state_t  state;                  /* started/stopped */
        int             opened;                 /* tru if open */
        int     remove_pending;
+
+       int             max_ps;                 /* max packet size */
 } tiglusb_t, *ptiglusb_t;
 
 #endif
index 5d5881d..d64409e 100644 (file)
@@ -1,15 +1,15 @@
 #
 # USB Network devices configuration
 #
-comment "USB Network adaptors"
-       depends on USB
-
-comment "Networking support is needed for USB Networking device support"
+comment "Networking support is needed for USB Network Adapter support"
        depends on USB && !NET
 
+menu "USB Network Adapters"
+       depends on USB && NET
+
 config USB_CATC
        tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)"
-       depends on USB && NET && EXPERIMENTAL
+       depends on EXPERIMENTAL
        select CRC32
        ---help---
          Say Y if you want to use one of the following 10Mbps USB Ethernet
@@ -29,7 +29,6 @@ config USB_CATC
 
 config USB_KAWETH
        tristate "USB KLSI KL5USB101-based ethernet device support"
-       depends on USB && NET
        ---help---
          Say Y here if you want to use one of the following 10Mbps only
          USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
@@ -69,7 +68,6 @@ config USB_KAWETH
 
 config USB_PEGASUS
        tristate "USB Pegasus/Pegasus-II based ethernet device support"
-       depends on USB && NET
        select MII
        ---help---
          Say Y here if you know you have Pegasus or Pegasus-II based adapter.
@@ -85,7 +83,7 @@ config USB_PEGASUS
 
 config USB_RTL8150
        tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)"
-       depends on USB && NET && EXPERIMENTAL
+       depends on EXPERIMENTAL
        help
          Say Y here if you have RTL8150 based usb-ethernet adapter.
          Send me <petkan@users.sourceforge.net> any comments you may have.
@@ -96,7 +94,6 @@ config USB_RTL8150
 
 config USB_USBNET
        tristate "Multi-purpose USB Networking Framework"
-       depends on USB && NET
        ---help---
          This driver supports several kinds of network links over USB,
          with "minidrivers" built around a common network driver core
@@ -185,6 +182,14 @@ config USB_PL2301
          Choose this option if you're using a host-to-host cable
          with one of these chips.
 
+config USB_KC2190
+       boolean "KT Technology KC2190 based cables (InstaNet)"
+       default y
+       depends on USB_USBNET && EXPERIMENTAL
+       help
+         Choose this option if you're using a host-to-host cable
+         with one of these chips.
+
 comment "Intelligent USB Devices/Gadgets"
        depends on USB_USBNET
 
@@ -198,6 +203,9 @@ config USB_ARMLINUX
          such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities
          in some PXA versions of the "blob" boot loader.
 
+         Linux-based "Gumstix" PXA-25x based systems use this protocol
+         to talk with other Linux systems.
+
          Although the ROMs shipped with Sharp Zaurus products use a
          different link level framing protocol, you can have them use
          this simpler protocol by installing a different kernel.
@@ -258,17 +266,20 @@ config USB_AX8817X
        select MII
        default y
        help
-
          This option adds support for ASIX AX88172 based USB 2.0
          10/100 Ethernet devices.
 
          This driver should work with at least the following devices:
            * Aten UC210T
            * ASIX AX88172
+           * Billionton Systems, USB2AR 
+           * Buffalo LUA-U2-KTX
+           * Corega FEther USB2-TX
            * D-Link DUB-E100
            * Hawking UF200
            * Linksys USB200M
            * Netgear FA120
+           * Sitecom LN-029
            * Intellinet USB 2.0 Ethernet
            * ST Lab USB 2.0 Ethernet
            * TrendNet TU2-ET100
@@ -276,4 +287,4 @@ config USB_AX8817X
          This driver creates an interface named "ethX", where X depends on
          what other networking devices you have in use.  
 
-
+endmenu
index 455fe6e..c825ef7 100644 (file)
@@ -43,7 +43,7 @@
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/crc32.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/uaccess.h>
 
 #undef DEBUG
@@ -411,7 +411,7 @@ static void catc_tx_done(struct urb *urb, struct pt_regs *regs)
 
 static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-       struct catc *catc = netdev->priv;
+       struct catc *catc = netdev_priv(netdev);
        unsigned long flags;
        char *tx_buf;
 
@@ -442,7 +442,7 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 static void catc_tx_timeout(struct net_device *netdev)
 {
-       struct catc *catc = netdev->priv;
+       struct catc *catc = netdev_priv(netdev);
 
        warn("Transmit timed out.");
        catc->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
@@ -604,7 +604,7 @@ static void catc_stats_timer(unsigned long data)
 
 static struct net_device_stats *catc_get_stats(struct net_device *netdev)
 {
-       struct catc *catc = netdev->priv;
+       struct catc *catc = netdev_priv(netdev);
        return &catc->stats;
 }
 
@@ -622,7 +622,7 @@ static void catc_multicast(unsigned char *addr, u8 *multicast)
 
 static void catc_set_multicast_list(struct net_device *netdev)
 {
-       struct catc *catc = netdev->priv;
+       struct catc *catc = netdev_priv(netdev);
        struct dev_mc_list *mc;
        u8 broadcast[6];
        u8 rx = RxEnable | RxPolarity | RxMultiCast;
@@ -664,74 +664,38 @@ static void catc_set_multicast_list(struct net_device *netdev)
        }
 }
 
-/*
- * ioctl's
- */
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+void catc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-        struct catc *catc = dev->priv;
-        u32 cmd;
-        
-        if (get_user(cmd, (u32 __user *)useraddr))
-                return -EFAULT;
-
-        switch (cmd) {
-        /* get driver info */
-        case ETHTOOL_GDRVINFO: {
-                struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-                strncpy(info.driver, driver_name, ETHTOOL_BUSINFO_LEN);
-                strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-               usb_make_path (catc->usbdev, info.bus_info, sizeof info.bus_info);
-                if (copy_to_user(useraddr, &info, sizeof(info)))
-                        return -EFAULT;
-                return 0;
-        }
-
-       /* get settings */
-       case ETHTOOL_GSET:
-               if (catc->is_f5u011) {
-                       struct ethtool_cmd ecmd = { ETHTOOL_GSET, 
-                                                   SUPPORTED_10baseT_Half | SUPPORTED_TP, 
-                                                   ADVERTISED_10baseT_Half | ADVERTISED_TP, 
-                                                   SPEED_10, 
-                                                   DUPLEX_HALF, 
-                                                   PORT_TP, 
-                                                   0, 
-                                                   XCVR_INTERNAL, 
-                                                   AUTONEG_DISABLE, 
-                                                   1, 
-                                                   1 
-                       };
-                       if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-                               return -EFAULT;
-                       return 0;
-               } else {
-                       return -EOPNOTSUPP;
-               }
-
-        /* get link status */
-        case ETHTOOL_GLINK: {
-                struct ethtool_value edata = {ETHTOOL_GLINK};
-                edata.data = netif_carrier_ok(dev);
-                if (copy_to_user(useraddr, &edata, sizeof(edata)))
-                        return -EFAULT;
-                return 0;
-        }
-       }
-        
-        return -EOPNOTSUPP;
+       struct catc *catc = netdev_priv(dev);
+       strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
+       strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+       usb_make_path (catc->usbdev, info->bus_info, sizeof info->bus_info);
 }
 
-static int catc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-        switch(cmd) {
-        case SIOCETHTOOL:
-                return netdev_ethtool_ioctl(dev, rq->ifr_data);
-        default:
-                return -EOPNOTSUPP;
-        }
+       struct catc *catc = netdev_priv(dev);
+       if (!catc->is_f5u011)
+               return -EOPNOTSUPP;
+
+       cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP;
+       cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP;
+       cmd->speed = SPEED_10;
+       cmd->duplex = DUPLEX_HALF;
+       cmd->port = PORT_TP; 
+       cmd->phy_address = 0;
+       cmd->transceiver = XCVR_INTERNAL;
+       cmd->autoneg = AUTONEG_DISABLE;
+       cmd->maxtxpkt = 1;
+       cmd->maxrxpkt = 1;
+       return 0;
 }
 
+static struct ethtool_ops ops = {
+       .get_drvinfo = catc_get_drvinfo,
+       .get_settings = catc_get_settings,
+       .get_link = ethtool_op_get_link
+};
 
 /*
  * Open, close.
@@ -739,7 +703,7 @@ static int catc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
 static int catc_open(struct net_device *netdev)
 {
-       struct catc *catc = netdev->priv;
+       struct catc *catc = netdev_priv(netdev);
        int status;
 
        catc->irq_urb->dev = catc->usbdev;
@@ -758,17 +722,17 @@ static int catc_open(struct net_device *netdev)
 
 static int catc_stop(struct net_device *netdev)
 {
-       struct catc *catc = netdev->priv;
+       struct catc *catc = netdev_priv(netdev);
 
        netif_stop_queue(netdev);
 
        if (!catc->is_f5u011)
                del_timer_sync(&catc->timer);
 
-       usb_unlink_urb(catc->rx_urb);
-       usb_unlink_urb(catc->tx_urb);
-       usb_unlink_urb(catc->irq_urb);
-       usb_unlink_urb(catc->ctrl_urb);
+       usb_kill_urb(catc->rx_urb);
+       usb_kill_urb(catc->tx_urb);
+       usb_kill_urb(catc->irq_urb);
+       usb_kill_urb(catc->ctrl_urb);
 
        return 0;
 }
@@ -791,17 +755,11 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                return -EIO;
        }
 
-       catc = kmalloc(sizeof(struct catc), GFP_KERNEL);
-       if (!catc)
+       netdev = alloc_etherdev(sizeof(struct catc));
+       if (!netdev)
                return -ENOMEM;
 
-       memset(catc, 0, sizeof(struct catc));
-
-       netdev = alloc_etherdev(0);
-       if (!netdev) {
-               kfree(catc);
-               return -EIO;
-       }
+       catc = netdev_priv(netdev);
 
        netdev->open = catc_open;
        netdev->hard_start_xmit = catc_hard_start_xmit;
@@ -810,14 +768,13 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
        netdev->tx_timeout = catc_tx_timeout;
        netdev->watchdog_timeo = TX_TIMEOUT;
        netdev->set_multicast_list = catc_set_multicast_list;
-       netdev->do_ioctl = catc_ioctl;
-       netdev->priv = catc;
+       SET_ETHTOOL_OPS(netdev, &ops);
 
        catc->usbdev = usbdev;
        catc->netdev = netdev;
 
-       catc->tx_lock = SPIN_LOCK_UNLOCKED;
-       catc->ctrl_lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&catc->tx_lock);
+       spin_lock_init(&catc->ctrl_lock);
 
        init_timer(&catc->timer);
        catc->timer.data = (long) catc;
@@ -839,7 +796,6 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                if (catc->irq_urb)
                        usb_free_urb(catc->irq_urb);
                free_netdev(netdev);
-               kfree(catc);
                return -ENOMEM;
        }
 
@@ -944,7 +900,6 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                usb_free_urb(catc->rx_urb);
                usb_free_urb(catc->irq_urb);
                free_netdev(netdev);
-               kfree(catc);
                return -EIO;
        }
        return 0;
@@ -962,7 +917,6 @@ static void catc_disconnect(struct usb_interface *intf)
                usb_free_urb(catc->rx_urb);
                usb_free_urb(catc->irq_urb);
                free_netdev(catc->netdev);
-               kfree(catc);
        }
 }
 
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 */
index acbf011..099fafa 100644 (file)
@@ -13,9 +13,9 @@
 #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
 #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
        struct edge_firmware_image_record {
-               unsigned short ExtAddr;
-               unsigned short Addr;
-               unsigned short Len;
+               __le16 ExtAddr;
+               __le16 Addr;
+               __le16 Len;
                unsigned char  Data[0];
        } __attribute__ ((packed));
 
index 3691fa5..c7c3a3c 100644 (file)
@@ -13,9 +13,9 @@
 #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
 #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
        struct edge_firmware_image_record {
-               unsigned short ExtAddr;
-               unsigned short Addr;
-               unsigned short Len;
+               __le16 ExtAddr;
+               __le16 Addr;
+               __le16 Len;
                unsigned char  Data[0];
        } __attribute__ ((packed));
 
index d01ec7b..5a61d80 100644 (file)
@@ -13,9 +13,9 @@
 #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
        #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
        struct edge_firmware_image_record {
-               unsigned short  ExtAddr;
-               unsigned short  Addr;
-               unsigned short  Len;
+               __le16 ExtAddr;
+               __le16 Addr;
+               __le16 Len;
                unsigned char   Data[0];
        } __attribute__ ((packed));
 
index bbd5dcc..067277e 100644 (file)
@@ -13,9 +13,9 @@
 #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
        #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
        struct edge_firmware_image_record {
-               unsigned short ExtAddr;
-               unsigned short Addr;
-               unsigned short Len;
+               __le16 ExtAddr;
+               __le16 Addr;
+               __le16 Len;
                unsigned char  Data[0];
        } __attribute__ ((packed));
 
index d43b9e6..e7ffe02 100644 (file)
@@ -98,6 +98,9 @@ static struct usb_serial_device_type edgeport_2port_device = {
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
        .break_ctl              = edge_break,
+       .read_int_callback      = edge_interrupt_callback,
+       .read_bulk_callback     = edge_bulk_in_callback,
+       .write_bulk_callback    = edge_bulk_out_data_callback,
 };
 
 static struct usb_serial_device_type edgeport_4port_device = {
@@ -123,6 +126,9 @@ static struct usb_serial_device_type edgeport_4port_device = {
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
        .break_ctl              = edge_break,
+       .read_int_callback      = edge_interrupt_callback,
+       .read_bulk_callback     = edge_bulk_in_callback,
+       .write_bulk_callback    = edge_bulk_out_data_callback,
 };
 
 static struct usb_serial_device_type edgeport_8port_device = {
@@ -148,6 +154,9 @@ static struct usb_serial_device_type edgeport_8port_device = {
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
        .break_ctl              = edge_break,
+       .read_int_callback      = edge_interrupt_callback,
+       .read_bulk_callback     = edge_bulk_in_callback,
+       .write_bulk_callback    = edge_bulk_out_data_callback,
 };
 
 #endif
index 6507340..8c1fa5e 100644 (file)
@@ -619,7 +619,7 @@ struct watchport_firmware_version
 // Structure of header of download image in fw_down.h
 struct ti_i2c_image_header
 {
-       __u16   Length;
+       __le16  Length;
        __u8    CheckSum;
 }__attribute__((packed));
 
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");
index 1dbb630..9df27f0 100644 (file)
@@ -290,7 +290,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
                case REQUEST_SENSE:             /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
                case MODE_SENSE:
                case MODE_SENSE_10:
-                       length = fst->Count;
+                       length = le16_to_cpu(fst->Count);
                        break;
                default:
                        length = srb->request_bufflen;
index 99ed4d9..9d3d774 100644 (file)
  * Helper routines
  ***********************************************************************/
 
-/*
- * Fix-up the return data from an INQUIRY command to show 
- * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
- */
-static void fix_inquiry_data(struct scsi_cmnd *srb)
-{
-       unsigned char databuf[3];
-       unsigned int index, offset;
-
-       /* verify that it's an INQUIRY command */
-       if (srb->cmnd[0] != INQUIRY)
-               return;
-
-       index = offset = 0;
-       if (usb_stor_access_xfer_buf(databuf, sizeof(databuf), srb,
-                       &index, &offset, FROM_XFER_BUF) != sizeof(databuf))
-               return;
-
-       if ((databuf[2] & 7) == 2)
-               return;
-
-       US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2 - was %d\n",
-                 databuf[2] & 7);
-
-       /* Change the SCSI revision number */
-       databuf[2] = (databuf[2] & ~7) | 2;
-
-       index = offset = 0;
-       usb_stor_access_xfer_buf(databuf, sizeof(databuf), srb,
-                       &index, &offset, TO_XFER_BUF);
-}
-
 /*
  * Fix-up the return data from a READ CAPACITY command. My Feiya reader
  * returns a value that is 1 too large.
@@ -137,10 +105,6 @@ void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us)
 
        /* send the command to the transport layer */
        usb_stor_invoke_transport(srb, us);
-       if (srb->result == SAM_STAT_GOOD) {
-               /* fix the INQUIRY data if necessary */
-               fix_inquiry_data(srb);
-       }
 }
 
 void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
@@ -160,11 +124,6 @@ void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
 
        /* send the command to the transport layer */
        usb_stor_invoke_transport(srb, us);
-
-       if (srb->result == SAM_STAT_GOOD) {
-               /* fix the INQUIRY data if necessary */
-               fix_inquiry_data(srb);
-       }
 }
 
 
@@ -208,11 +167,6 @@ void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
 
        /* send the command to the transport layer */
        usb_stor_invoke_transport(srb, us);
-
-       if (srb->result == SAM_STAT_GOOD) {
-               /* Fix the data for an INQUIRY, if necessary */
-               fix_inquiry_data(srb);
-       }
 }
 
 void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
@@ -222,9 +176,6 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
        usb_stor_invoke_transport(srb, us);
 
        if (srb->result == SAM_STAT_GOOD) {
-               /* Fix the INQUIRY data if necessary */
-               fix_inquiry_data(srb);
-
                /* Fix the READ CAPACITY result if necessary */
                if (us->flags & US_FL_FIX_CAPACITY)
                        fix_read_capacity(srb);
index baa4fa0..99c538f 100644 (file)
@@ -1239,8 +1239,6 @@ int __init amifb_setup(char *options)
                if (!strcmp(this_opt, "inverse")) {
                        amifb_inverse = 1;
                        fb_invert_cmaps();
-               } else if (!strcmp(this_opt, "off")) {
-                       amifb_video_off();
                } else if (!strcmp(this_opt, "ilbm"))
                        amifb_ilbm = 1;
                else if (!strncmp(this_opt, "monitorcap:", 11))
@@ -2260,26 +2258,15 @@ int __init amifb_init(void)
 #ifndef MODULE
        char *option = NULL;
 
-       if (fb_get_options("amifb", &option))
+       if (fb_get_options("amifb", &option)) {
+               amifb_video_off();
                return -ENODEV;
+       }
        amifb_setup(option);
 #endif
        if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
                return -ENXIO;
 
-       /*
-        * TODO: where should we put this? The DMI Resolver doesn't have a
-        *       frame buffer accessible by the CPU
-        */
-
-#ifdef CONFIG_GSP_RESOLVER
-       if (amifb_resolver){
-               custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-                               DMAF_BLITTER | DMAF_SPRITE;
-               return 0;
-       }
-#endif
-
        /*
         * We request all registers starting from bplpt[0]
         */
@@ -2482,6 +2469,7 @@ static void amifb_deinit(void)
 static int amifb_blank(int blank, struct fb_info *info)
 {
        do_blank = blank ? blank : -1;
+
        return 0;
 }
 
@@ -2956,21 +2944,11 @@ static int ami_encode_var(struct fb_var_screeninfo *var,
        var->bits_per_pixel = par->bpp;
        var->grayscale = 0;
 
-       if (IS_AGA) {
-               var->red.offset = 0;
-               var->red.length = 8;
-               var->red.msb_right = 0;
-       } else {
-               if (clk_shift == TAG_SHRES) {
-                       var->red.offset = 0;
-                       var->red.length = 2;
-                       var->red.msb_right = 0;
-               } else {
-                       var->red.offset = 0;
-                       var->red.length = 4;
-                       var->red.msb_right = 0;
-               }
-       }
+       var->red.offset = 0;
+       var->red.msb_right = 0;
+       var->red.length = par->bpp;
+       if (par->bplcon0 & BPC0_HAM)
+           var->red.length -= 2;
        var->blue = var->green = var->red;
        var->transp.offset = 0;
        var->transp.length = 0;
@@ -3270,20 +3248,20 @@ static void ami_do_blank(void)
                custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
                red = green = blue = 0;
                if (!IS_OCS && do_blank > 1) {
-                       switch (do_blank-1) {
-                               case VESA_VSYNC_SUSPEND:
+                       switch (do_blank) {
+                               case FB_BLANK_VSYNC_SUSPEND:
                                        custom.hsstrt = hsstrt2hw(par->hsstrt);
                                        custom.hsstop = hsstop2hw(par->hsstop);
                                        custom.vsstrt = vsstrt2hw(par->vtotal+4);
                                        custom.vsstop = vsstop2hw(par->vtotal+4);
                                        break;
-                               case VESA_HSYNC_SUSPEND:
+                               case FB_BLANK_HSYNC_SUSPEND:
                                        custom.hsstrt = hsstrt2hw(par->htotal+16);
                                        custom.hsstop = hsstop2hw(par->htotal+16);
                                        custom.vsstrt = vsstrt2hw(par->vsstrt);
                                        custom.vsstop = vsstrt2hw(par->vsstop);
                                        break;
-                               case VESA_POWERDOWN:
+                               case FB_BLANK_POWERDOWN:
                                        custom.hsstrt = hsstrt2hw(par->htotal+16);
                                        custom.hsstop = hsstop2hw(par->htotal+16);
                                        custom.vsstrt = vsstrt2hw(par->vtotal+4);
index bda3ed9..15e0925 100644 (file)
@@ -575,9 +575,6 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
 
        init_asiliant(p, addr);
 
-       /* Clear the entire framebuffer */
-       memset(p->screen_base, 0, 0x200000);
-
        pci_set_drvdata(dp, p);
        return 0;
 }
index 8aa5368..5538f3c 100644 (file)
@@ -2,9 +2,9 @@ obj-$(CONFIG_FB_ATY) += atyfb.o
 obj-$(CONFIG_FB_ATY128) += aty128fb.o
 obj-$(CONFIG_FB_RADEON) += radeonfb.o
 
-atyfb-y                                := atyfb_base.o mach64_accel.o
+atyfb-y                                := atyfb_base.o mach64_accel.o mach64_cursor.o
 atyfb-$(CONFIG_FB_ATY_GX)      += mach64_gx.o
-atyfb-$(CONFIG_FB_ATY_CT)      += mach64_ct.o mach64_cursor.o
+atyfb-$(CONFIG_FB_ATY_CT)      += mach64_ct.o
 atyfb-objs                     := $(atyfb-y)
 
 radeonfb-y                     := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
index d99e518..e417186 100644 (file)
@@ -64,6 +64,7 @@
 #define PCI_CHIP_MACH64LQ              0x4C51
 #define PCI_CHIP_MACH64LR              0x4C52
 #define PCI_CHIP_MACH64LS              0x4C53
+#define PCI_CHIP_MACH64LT              0x4C54
 #define PCI_CHIP_RADEON_LW             0x4C57
 #define PCI_CHIP_RADEON_LX             0x4C58
 #define PCI_CHIP_RADEON_LY             0x4C59
index f2d82d0..a215c2f 100644 (file)
@@ -397,7 +397,7 @@ struct aty128fb_par {
        struct aty128_ddafifo fifo_reg;
        u32 accel_flags;
        struct aty128_constants constants;  /* PLL and others      */
-       void *regbase;                      /* remapped mmio       */
+       void __iomem *regbase;              /* remapped mmio       */
        u32 vram_size;                      /* onboard video ram   */
        int chip_gen;
        const struct aty128_meminfo *mem;   /* onboard mem info    */
@@ -450,9 +450,9 @@ static int aty128_decode_var(struct fb_var_screeninfo *var,
                              struct aty128fb_par *par);
 #if 0
 static void __init aty128_get_pllinfo(struct aty128fb_par *par,
-                                     void *bios);
-static void __init *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
-static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom);
+                                     void __iomem *bios);
+static void __init __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
+static void __init aty128_unmap_ROM(struct pci_dev *dev, void __iomem * rom);
 #endif
 static void aty128_timings(struct aty128fb_par *par);
 static void aty128_init_engine(struct aty128fb_par *par);
@@ -788,7 +788,7 @@ static u32 depth_to_dst(u32 depth)
 
 
 #ifndef __sparc__
-static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom)
+static void __init aty128_unmap_ROM(struct pci_dev *dev, void __iomem * rom)
 {
        struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
        
@@ -806,12 +806,12 @@ static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom)
 }
 
 
-static void * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
+static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
 {
        struct resource *r;
        u16 dptr;
        u8 rom_type;
-       void *bios;
+       void __iomem *bios;
 
        /* Fix from ATI for problem with Rage128 hardware not leaving ROM enabled */
        unsigned int temp;
@@ -903,7 +903,7 @@ static void * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_d
        return NULL;
 }
 
-static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char *bios)
+static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios)
 {
        unsigned int bios_hdr;
        unsigned int bios_pll;
@@ -925,7 +925,7 @@ static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char *b
 }           
 
 #ifdef CONFIG_X86
-static void *  __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
+static void __iomem *  __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
 {
        /* I simplified this code as we used to miss the signatures in
         * a lot of case. It's now closer to XFree, we just don't check
@@ -933,13 +933,13 @@ static void *  __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
         * if we end up having conflicts
         */
         u32  segstart;
-        unsigned char *rom_base = NULL;
+        unsigned char __iomem *rom_base = NULL;
                                                 
         for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
-                rom_base = (char *)ioremap(segstart, 0x10000);
+                rom_base = ioremap(segstart, 0x10000);
                if (rom_base == NULL)
                        return NULL;
-                if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
+               if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa)
                        break;
                 iounmap(rom_base);
                rom_base = NULL;
@@ -1885,7 +1885,7 @@ static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id
        struct fb_info *info;
        int err;
 #ifndef __sparc__
-       void *bios = NULL;
+       void __iomem *bios = NULL;
 #endif
 
        /* Enable device in PCI config */
@@ -2016,8 +2016,6 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
 
        release_mem_region(pci_resource_start(pdev, 0),
                           pci_resource_len(pdev, 0));
-       release_mem_region(pci_resource_start(pdev, 1),
-                          pci_resource_len(pdev, 1));
        release_mem_region(pci_resource_start(pdev, 2),
                           pci_resource_len(pdev, 2));
        framebuffer_release(info);
@@ -2042,11 +2040,11 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
                set_backlight_enable(0);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
-       if (blank & VESA_VSYNC_SUSPEND)
+       if (blank & FB_BLANK_VSYNC_SUSPEND)
                state |= 2;
-       if (blank & VESA_HSYNC_SUSPEND)
+       if (blank & FB_BLANK_HSYNC_SUSPEND)
                state |= 1;
-       if (blank & VESA_POWERDOWN)
+       if (blank & FB_BLANK_POWERDOWN)
                state |= 4;
 
        aty_st_8(CRTC_EXT_CNTL+1, state);
@@ -2363,7 +2361,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, u32 state)
                state = 2;
 #endif /* CONFIG_PPC_PMAC */
         
-       if (state != 2 || state == pdev->dev.power_state)
+       if (state != 2 || state == pdev->dev.power.power_state)
                return 0;
 
        printk(KERN_DEBUG "aty128fb: suspending...\n");
@@ -2394,7 +2392,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, u32 state)
 
        release_console_sem();
 
-       pdev->dev.power_state = state;
+       pdev->dev.power.power_state = state;
 
        return 0;
 }
@@ -2404,13 +2402,13 @@ static int aty128_pci_resume(struct pci_dev *pdev)
        struct fb_info *info = pci_get_drvdata(pdev);
        struct aty128fb_par *par = info->par;
 
-       if (pdev->dev.power_state == 0)
+       if (pdev->dev.power.power_state == 0)
                return 0;
 
        acquire_console_sem();
 
        /* Wakeup chip */
-       if (pdev->dev.power_state == 2)
+       if (pdev->dev.power.power_state == 2)
                aty128_set_suspend(par, 0);
        par->asleep = 0;
 
@@ -2430,7 +2428,7 @@ static int aty128_pci_resume(struct pci_dev *pdev)
 
        release_console_sem();
 
-       pdev->dev.power_state = 0;
+       pdev->dev.power.power_state = 0;
 
        printk(KERN_DEBUG "aty128fb: resumed !\n");
 
index b342acc..30e225f 100644 (file)
@@ -3,6 +3,8 @@
  */
 
 #include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
     /*
      *  Elements of the hardware specific atyfb_par structure
      */
 struct crtc {
        u32 vxres;
        u32 vyres;
+       u32 xoffset;
+       u32 yoffset;
+       u32 bpp;
        u32 h_tot_disp;
        u32 h_sync_strt_wid;
        u32 v_tot_disp;
        u32 v_sync_strt_wid;
+       u32 vline_crnt_vline;
        u32 off_pitch;
        u32 gen_cntl;
        u32 dp_pix_width;       /* acceleration */
        u32 dp_chain_mask;      /* acceleration */
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+       u32 horz_stretching;
+       u32 vert_stretching;
+       u32 ext_vert_stretch;
+       u32 shadow_h_tot_disp;
+       u32 shadow_h_sync_strt_wid;
+       u32 shadow_v_tot_disp;
+       u32 shadow_v_sync_strt_wid;
+       u32 lcd_gen_cntl;
+       u32 lcd_config_panel;
+       u32 lcd_index;
+#endif
+};
+
+struct aty_interrupt {
+       wait_queue_head_t wait;
+       unsigned int count;
+       int pan_display;
+};
+
+struct pll_info {
+       int pll_max;
+       int pll_min;
+       int sclk, mclk, mclk_pm, xclk;
+       int ref_div;
+       int ref_clk;
 };
 
+typedef struct {
+       u16 unknown1;
+       u16 PCLK_min_freq;
+       u16 PCLK_max_freq;
+       u16 unknown2;
+       u16 ref_freq;
+       u16 ref_divider;
+       u16 unknown3;
+       u16 MCLK_pwd;
+       u16 MCLK_max_freq;
+       u16 XCLK_max_freq;
+       u16 SCLK_freq;
+} __attribute__ ((packed)) PLL_BLOCK_MACH64;
+
 struct pll_514 {
        u8 m;
        u8 n;
@@ -36,16 +82,39 @@ struct pll_ct {
        u8 pll_ref_div;
        u8 pll_gen_cntl;
        u8 mclk_fb_div;
+       u8 mclk_fb_mult; /* 2 ro 4 */
+/*     u8 sclk_fb_div;*/
        u8 pll_vclk_cntl;
        u8 vclk_post_div;
        u8 vclk_fb_div;
        u8 pll_ext_cntl;
-       u32 dsp_config;         /* Mach64 GTB DSP */
-       u32 dsp_on_off;         /* Mach64 GTB DSP */
+/*     u8 ext_vpll_cntl;
+       u8 spll_cntl2;*/
+       u32 dsp_config; /* Mach64 GTB DSP */
+       u32 dsp_on_off; /* Mach64 GTB DSP */
+       u32 dsp_loop_latency;
+       u32 fifo_size;
+       u32 xclkpagefaultdelay;
+       u32 xclkmaxrasdelay;
+       u8 xclk_ref_div;
+       u8 xclk_post_div;
        u8 mclk_post_div_real;
+       u8 xclk_post_div_real;
        u8 vclk_post_div_real;
+       u8 features;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+       u32 xres; /* use for LCD stretching/scaling */
+#endif
 };
 
+/*
+       for pll_ct.features
+*/
+#define DONT_USE_SPLL 0x1
+#define DONT_USE_XDLL 0x2
+#define USE_CPUCLK    0x4
+#define POWERDOWN_PLL 0x8
+
 union aty_pll {
        struct pll_ct ct;
        struct pll_514 ibm514;
@@ -56,42 +125,68 @@ union aty_pll {
      *  The hardware parameters for each card
      */
 
-struct aty_cursor {
-       u8 bits[8][64];
-       u8 mask[8][64];
-       u8 *ram;
-};
-
 struct atyfb_par {
-       struct aty_cmap_regs *aty_cmap_regs;
+       struct aty_cmap_regs __iomem *aty_cmap_regs;
+       struct { u8 red, green, blue; } palette[256];
        const struct aty_dac_ops *dac_ops;
        const struct aty_pll_ops *pll_ops;
-       struct aty_cursor *cursor;
-       unsigned long ati_regbase;
-       unsigned long clk_wr_offset;
+       void __iomem *ati_regbase;
+       unsigned long clk_wr_offset; /* meaning overloaded, clock id by CT */
        struct crtc crtc;
        union aty_pll pll;
+       struct pll_info pll_limits;
        u32 features;
        u32 ref_clk_per;
        u32 pll_per;
        u32 mclk_per;
+       u32 xclk_per;
        u8 bus_type;
        u8 ram_type;
        u8 mem_refresh_rate;
-       u8 blitter_may_be_busy;
+       u16 pci_id;
        u32 accel_flags;
+       int blitter_may_be_busy;
+       int asleep;
+       int lock_blank;
+       unsigned long res_start;
+       unsigned long res_size;
 #ifdef __sparc__
        struct pci_mmap_map *mmap_map;
        u8 mmaped;
+#endif
        int open;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+       unsigned long bios_base_phys;
+       unsigned long bios_base;
+       unsigned long lcd_table;
+       u16 lcd_width;
+       u16 lcd_height;
+       u32 lcd_pixclock;
+       u16 lcd_refreshrate;
+       u16 lcd_htotal;
+       u16 lcd_hdisp;
+       u16 lcd_hsync_dly;
+       u16 lcd_hsync_len;
+       u16 lcd_vtotal;
+       u16 lcd_vdisp;
+       u16 lcd_vsync_len;
+       u16 lcd_right_margin;
+       u16 lcd_lower_margin;
+       u16 lcd_hblank_len;
+       u16 lcd_vblank_len;
 #endif
-#ifdef CONFIG_PMAC_PBOOK
-       struct fb_info *next;
-       unsigned char *save_framebuffer;
-       unsigned long save_pll[64];
+       unsigned long aux_start; /* auxiliary aperture */
+       unsigned long aux_size;
+       struct aty_interrupt vblank;
+       unsigned long irq_flags;
+       unsigned int irq;
+       spinlock_t int_lock;
+#ifdef CONFIG_MTRR
+       int mtrr_aper;
+       int mtrr_reg;
 #endif
 };
-    
+
     /*
      *  ATI Mach64 features
      */
@@ -101,7 +196,7 @@ struct atyfb_par {
 #define M64F_RESET_3D          0x00000001
 #define M64F_MAGIC_FIFO                0x00000002
 #define M64F_GTB_DSP           0x00000004
-#define M64F_FIFO_24           0x00000008
+#define M64F_FIFO_32           0x00000008
 #define M64F_SDRAM_MAGIC_PLL   0x00000010
 #define M64F_MAGIC_POSTDIV     0x00000020
 #define M64F_INTEGRATED                0x00000040
@@ -116,9 +211,10 @@ struct atyfb_par {
 #define M64F_G3_PB_1_1         0x00008000
 #define M64F_G3_PB_1024x768    0x00010000
 #define M64F_EXTRA_BRIGHT      0x00020000
-#define M64F_LT_SLEEP          0x00040000
+#define M64F_LT_LCD_REGS       0x00040000
 #define M64F_XL_DLL            0x00080000
-
+#define M64F_MFB_FORCE_4       0x00100000
+#define M64F_HW_TRIPLE         0x00200000
 
     /*
      *  Register access
@@ -137,8 +233,7 @@ static inline u32 aty_ld_le32(int regindex, const struct atyfb_par *par)
 #endif
 }
 
-static inline void aty_st_le32(int regindex, u32 val,
-                              const struct atyfb_par *par)
+static inline void aty_st_le32(int regindex, u32 val, const struct atyfb_par *par)
 {
        /* Hack for bloc 1, should be cleanly optimized by compiler */
        if (regindex >= 0x400)
@@ -163,8 +258,7 @@ static inline u8 aty_ld_8(int regindex, const struct atyfb_par *par)
 #endif
 }
 
-static inline void aty_st_8(int regindex, u8 val,
-                           const struct atyfb_par *par)
+static inline void aty_st_8(int regindex, u8 val, const struct atyfb_par *par)
 {
        /* Hack for bloc 1, should be cleanly optimized by compiler */
        if (regindex >= 0x400)
@@ -177,17 +271,10 @@ static inline void aty_st_8(int regindex, u8 val,
 #endif
 }
 
-static inline u8 aty_ld_pll(int offset, const struct atyfb_par *par)
-{
-       u8 res;
-
-       /* write addr byte */
-       aty_st_8(CLOCK_CNTL + 1, (offset << 2), par);
-       /* read the register value */
-       res = aty_ld_8(CLOCK_CNTL + 2, par);
-       return res;
-}
-
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par);
+extern u32 aty_ld_lcd(int index, const struct atyfb_par *par);
+#endif
 
     /*
      *  DAC operations
@@ -195,14 +282,14 @@ static inline u8 aty_ld_pll(int offset, const struct atyfb_par *par)
 
 struct aty_dac_ops {
        int (*set_dac) (const struct fb_info * info,
-                       const union aty_pll * pll, u32 bpp, u32 accel);
+               const union aty_pll * pll, u32 bpp, u32 accel);
 };
 
-extern const struct aty_dac_ops aty_dac_ibm514;        /* IBM RGB514 */
-extern const struct aty_dac_ops aty_dac_ati68860b;     /* ATI 68860-B */
-extern const struct aty_dac_ops aty_dac_att21c498;     /* AT&T 21C498 */
-extern const struct aty_dac_ops aty_dac_unsupported;   /* unsupported */
-extern const struct aty_dac_ops aty_dac_ct;    /* Integrated */
+extern const struct aty_dac_ops aty_dac_ibm514; /* IBM RGB514 */
+extern const struct aty_dac_ops aty_dac_ati68860b; /* ATI 68860-B */
+extern const struct aty_dac_ops aty_dac_att21c498; /* AT&T 21C498 */
+extern const struct aty_dac_ops aty_dac_unsupported; /* unsupported */
+extern const struct aty_dac_ops aty_dac_ct; /* Integrated */
 
 
     /*
@@ -210,37 +297,32 @@ extern const struct aty_dac_ops aty_dac_ct;       /* Integrated */
      */
 
 struct aty_pll_ops {
-       int (*var_to_pll) (const struct fb_info * info, u32 vclk_per,
-                          u8 bpp, union aty_pll * pll);
-        u32(*pll_to_var) (const struct fb_info * info,
-                          const union aty_pll * pll);
-       void (*set_pll) (const struct fb_info * info,
-                        const union aty_pll * pll);
+       int (*var_to_pll) (const struct fb_info * info, u32 vclk_per, u32 bpp, union aty_pll * pll);
+       u32 (*pll_to_var) (const struct fb_info * info, const union aty_pll * pll);
+       void (*set_pll)   (const struct fb_info * info, const union aty_pll * pll);
+       void (*get_pll)   (const struct fb_info *info, union aty_pll * pll);
+       int (*init_pll)   (const struct fb_info * info, union aty_pll * pll);
 };
 
-extern const struct aty_pll_ops aty_pll_ati18818_1;    /* ATI 18818 */
-extern const struct aty_pll_ops aty_pll_stg1703;       /* STG 1703 */
-extern const struct aty_pll_ops aty_pll_ch8398;        /* Chrontel 8398 */
-extern const struct aty_pll_ops aty_pll_att20c408;     /* AT&T 20C408 */
-extern const struct aty_pll_ops aty_pll_ibm514;        /* IBM RGB514 */
-extern const struct aty_pll_ops aty_pll_unsupported;   /* unsupported */
-extern const struct aty_pll_ops aty_pll_ct;    /* Integrated */
+extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */
+extern const struct aty_pll_ops aty_pll_stg1703; /* STG 1703 */
+extern const struct aty_pll_ops aty_pll_ch8398; /* Chrontel 8398 */
+extern const struct aty_pll_ops aty_pll_att20c408; /* AT&T 20C408 */
+extern const struct aty_pll_ops aty_pll_ibm514; /* IBM RGB514 */
+extern const struct aty_pll_ops aty_pll_unsupported; /* unsupported */
+extern const struct aty_pll_ops aty_pll_ct; /* Integrated */
 
 
-extern void aty_set_pll_ct(const struct fb_info *info,
-                          const union aty_pll *pll);
-extern void aty_calc_pll_ct(const struct fb_info *info,
-                           struct pll_ct *pll);
+extern void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll);
+extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
 
 
     /*
      *  Hardware cursor support
      */
 
-extern struct aty_cursor *aty_init_cursor(struct fb_info *info);
+extern int aty_init_cursor(struct fb_info *info);
 extern int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor);
-extern void aty_set_cursor_color(struct fb_info *info);
-extern void aty_set_cursor_shape(struct fb_info *info);
 
     /*
      *  Hardware acceleration
@@ -260,6 +342,5 @@ static inline void wait_for_idle(struct atyfb_par *par)
 }
 
 extern void aty_reset_engine(const struct atyfb_par *par);
-extern void aty_init_engine(struct atyfb_par *par,
-                           struct fb_info *info);
+extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info);
 
index 8b60ece..c98f4a4 100644 (file)
      *  Generic Mach64 routines
      */
 
+/* this is for DMA GUI engine! work in progress */
+typedef struct {
+       u32 frame_buf_offset;
+       u32 system_mem_addr;
+       u32 command;
+       u32 reserved;
+} BM_DESCRIPTOR_ENTRY;
+
+#define LAST_DESCRIPTOR (1 << 31)
+#define SYSTEM_TO_FRAME_BUFFER 0
+
+static u32 rotation24bpp(u32 dx, u32 direction)
+{
+       u32 rotation;
+       if (direction & DST_X_LEFT_TO_RIGHT) {
+               rotation = (dx / 4) % 6;
+       } else {
+               rotation = ((dx + 2) / 4) % 6;
+       }
+
+       return ((rotation << 8) | DST_24_ROTATION_ENABLE);
+}
+
 void aty_reset_engine(const struct atyfb_par *par)
 {
        /* reset engine */
        aty_st_le32(GEN_TEST_CNTL,
-                   aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE,
-                   par);
+               aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE, par);
        /* enable engine */
        aty_st_le32(GEN_TEST_CNTL,
-                   aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE,
-                   par);
+               aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par);
        /* ensure engine is not locked up by clearing any FIFO or */
        /* HOST errors */
        aty_st_le32(BUS_CNTL,
-                   aty_ld_le32(BUS_CNTL,
-                               par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK,
-                   par);
+               aty_ld_le32(BUS_CNTL, par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, par);
 }
 
 static void reset_GTC_3D_engine(const struct atyfb_par *par)
@@ -51,7 +70,7 @@ void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
        if (info->var.bits_per_pixel == 24) {
                /* In 24 bpp, the engine is in 8 bpp - this requires that all */
                /* horizontal coordinates and widths must be adjusted */
-               pitch_value = pitch_value * 3;
+               pitch_value *= 3;
        }
 
        /* On GTC (RagePro), we need to reset the 3D engine before */
@@ -146,7 +165,7 @@ void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
        aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, par);
 
        wait_for_fifo(5, par);
-       aty_st_le32(SCALE_3D_CNTL, 0, par);
+       aty_st_le32(SCALE_3D_CNTL, 0, par);
        aty_st_le32(Z_CNTL, 0, par);
        aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, par) & ~0x20,
                    par);
@@ -174,9 +193,10 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
        u32 dy = area->dy, sy = area->sy, direction = DST_LAST_PEL;
-       u32 sx = area->sx, dx = area->dx, width = area->width;  
-       u32 pitch_value;
+       u32 sx = area->sx, dx = area->dx, width = area->width, rotation = 0;
 
+       if (par->asleep)
+               return;
        if (!area->width || !area->height)
                return;
        if (!par->accel_flags) {
@@ -186,11 +206,9 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
                return;
        }
 
-       pitch_value = info->var.xres_virtual;
        if (info->var.bits_per_pixel == 24) {
                /* In 24 bpp, the engine is in 8 bpp - this requires that all */
                /* horizontal coordinates and widths must be adjusted */
-               pitch_value *= 3;
                sx *= 3;
                dx *= 3;
                width *= 3;
@@ -208,19 +226,25 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
        } else
                direction |= DST_X_LEFT_TO_RIGHT;
 
+       if (info->var.bits_per_pixel == 24) {
+               rotation = rotation24bpp(dx, direction);
+       }
+
        wait_for_fifo(4, par);
        aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par);
        aty_st_le32(SRC_Y_X, (sx << 16) | sy, par);
        aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par);
-       aty_st_le32(DST_CNTL, direction, par);
+       aty_st_le32(DST_CNTL, direction | rotation, par);
        draw_rect(dx, dy, width, area->height, par);
 }
 
 void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
-       u32 color = rect->color, dx = rect->dx, width = rect->width;
+       u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0;
 
+       if (par->asleep)
+               return;
        if (!rect->width || !rect->height)
                return;
        if (!par->accel_flags) {
@@ -238,6 +262,7 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
                /* horizontal coordinates and widths must be adjusted */
                dx *= 3;
                width *= 3;
+               rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
        }
 
        wait_for_fifo(3, par);
@@ -247,15 +272,162 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
                    par);
        aty_st_le32(DST_CNTL,
                    DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
-                   DST_X_LEFT_TO_RIGHT, par);
+                   DST_X_LEFT_TO_RIGHT | rotation, par);
        draw_rect(dx, rect->dy, width, rect->height, par);
 }
 
 void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
-    
-       if (par->blitter_may_be_busy)
-               wait_for_idle(par);
-       cfb_imageblit(info, image);
+       u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width;
+       u32 pix_width_save, pix_width, host_cntl, rotation = 0, src, mix;
+
+       if (par->asleep)
+               return;
+       if (!image->width || !image->height)
+               return;
+       if (!par->accel_flags ||
+           (image->depth != 1 && info->var.bits_per_pixel != image->depth)) {
+               if (par->blitter_may_be_busy)
+                       wait_for_idle(par);
+
+               cfb_imageblit(info, image);
+               return;
+       }
+
+       wait_for_idle(par);
+       pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par);
+       host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN;
+
+       switch (image->depth) {
+       case 1:
+           pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
+           pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_1BPP);
+           break;
+       case 4:
+           pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
+           pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_4BPP);
+           break;
+       case 8:
+           pix_width &= ~HOST_MASK;
+           pix_width |= HOST_8BPP;
+           break;
+       case 15:
+           pix_width &= ~HOST_MASK;
+           pix_width |= HOST_15BPP;
+           break;
+       case 16:
+           pix_width &= ~HOST_MASK;
+           pix_width |= HOST_16BPP;
+           break;
+       case 24:
+           pix_width &= ~HOST_MASK;
+           pix_width |= HOST_24BPP;
+           break;
+       case 32:
+           pix_width &= ~HOST_MASK;
+           pix_width |= HOST_32BPP;
+           break;
+       }
+
+       if (info->var.bits_per_pixel == 24) {
+               /* In 24 bpp, the engine is in 8 bpp - this requires that all */
+               /* horizontal coordinates and widths must be adjusted */
+               dx *= 3;
+               width *= 3;
+
+               rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
+
+               pix_width &= ~DST_MASK;
+               pix_width |= DST_8BPP;
+
+               /*
+                * since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit
+                * this hwaccelerated triple has an issue with not aligned data
+                */
+               if (M64_HAS(HW_TRIPLE) && image->width % 8 == 0)
+                       pix_width |= DP_HOST_TRIPLE_EN;
+       }
+
+       if (image->depth == 1) {
+               u32 fg, bg;
+               if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+                   info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+                       fg = ((u32*)(info->pseudo_palette))[image->fg_color];
+                       bg = ((u32*)(info->pseudo_palette))[image->bg_color];
+               } else {
+                       fg = image->fg_color;
+                       bg = image->bg_color;
+               }
+
+               wait_for_fifo(2, par);
+               aty_st_le32(DP_BKGD_CLR, bg, par);
+               aty_st_le32(DP_FRGD_CLR, fg, par);
+               src = MONO_SRC_HOST | FRGD_SRC_FRGD_CLR | BKGD_SRC_BKGD_CLR;
+               mix = FRGD_MIX_S | BKGD_MIX_S;
+       } else {
+               src = MONO_SRC_ONE | FRGD_SRC_HOST;
+               mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D;
+       }
+
+       wait_for_fifo(6, par);
+       aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par);
+       aty_st_le32(DP_PIX_WIDTH, pix_width, par);
+       aty_st_le32(DP_MIX, mix, par);
+       aty_st_le32(DP_SRC, src, par);
+       aty_st_le32(HOST_CNTL, host_cntl, par);
+       aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par);
+
+       draw_rect(dx, dy, width, image->height, par);
+       src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
+
+       /* manual triple each pixel */
+       if (info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) {
+               int inbit, outbit, mult24, byte_id_in_dword, width;
+               u8 *pbitmapin = (u8*)image->data, *pbitmapout;
+               u32 hostdword;
+
+               for (width = image->width, inbit = 7, mult24 = 0; src_bytes; ) {
+                       for (hostdword = 0, pbitmapout = (u8*)&hostdword, byte_id_in_dword = 0;
+                               byte_id_in_dword < 4 && src_bytes;
+                               byte_id_in_dword++, pbitmapout++) {
+                               for (outbit = 7; outbit >= 0; outbit--) {
+                                       *pbitmapout |= (((*pbitmapin >> inbit) & 1) << outbit);
+                                       mult24++;
+                                       /* next bit */
+                                       if (mult24 == 3) {
+                                               mult24 = 0;
+                                               inbit--;
+                                               width--;
+                                       }
+
+                                       /* next byte */
+                                       if (inbit < 0 || width == 0) {
+                                               src_bytes--;
+                                               pbitmapin++;
+                                               inbit = 7;
+
+                                               if (width == 0) {
+                                                   width = image->width;
+                                                   outbit = 0;
+                                               }
+                                       }
+                               }
+                       }
+                       wait_for_fifo(1, par);
+                       aty_st_le32(HOST_DATA0, hostdword, par);
+               }
+       } else {
+               u32 *pbitmap, dwords = (src_bytes + 3) / 4;
+               for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) {
+                       wait_for_fifo(1, par);
+                       aty_st_le32(HOST_DATA0, le32_to_cpup(pbitmap), par);
+               }
+       }
+
+       wait_for_idle(par);
+
+       /* restore pix_width */
+       wait_for_fifo(1, par);
+       aty_st_le32(DP_PIX_WIDTH, pix_width_save, par);
 }
index 921b7dc..e3325d5 100644 (file)
  */
 
 #include <linux/fb.h>
-
+#include <linux/delay.h>
 #include <asm/io.h>
-
 #include <video/mach64.h>
 #include "atyfb.h"
 
+#undef DEBUG
 
-/* FIXME: remove the FAIL definition */
-#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
-
-static void aty_st_pll(int offset, u8 val, const struct atyfb_par *par);
-static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per,
-                           struct pll_ct *pll);
-static int aty_dsp_gt(const struct fb_info *info, u8 bpp,
-                     struct pll_ct *pll);
-static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per,
-                            u8 bpp, union aty_pll *pll);
-static u32 aty_pll_ct_to_var(const struct fb_info *info,
-                            const union aty_pll *pll);
+static int aty_valid_pll_ct (const struct fb_info *info, u32 vclk_per, struct pll_ct *pll);
+static int aty_dsp_gt       (const struct fb_info *info, u32 bpp, struct pll_ct *pll);
+static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll);
+static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll);
 
+u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par)
+{
+       u8 res;
 
+       /* write addr byte */
+       aty_st_8(CLOCK_CNTL_ADDR, (offset << 2) & PLL_ADDR, par);
+       /* read the register value */
+       res = aty_ld_8(CLOCK_CNTL_DATA, par);
+       return res;
+}
 
-static void aty_st_pll(int offset, u8 val, const struct atyfb_par *par)
+void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
 {
        /* write addr byte */
-       aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, par);
+       aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) | PLL_WR_EN, par);
        /* write the register value */
-       aty_st_8(CLOCK_CNTL + 2, val, par);
-       aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, par);
+       aty_st_8(CLOCK_CNTL_DATA, val & PLL_DATA, par);
+       aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) & ~PLL_WR_EN, par);
 }
 
+/*
+ * by Daniel Mantione
+ *                                  <daniel.mantione@freepascal.org>
+ *
+ *
+ * ATI Mach64 CT clock synthesis description.
+ *
+ * All clocks on the Mach64 can be calculated using the same principle:
+ *
+ *       XTALIN * x * FB_DIV
+ * CLK = ----------------------
+ *       PLL_REF_DIV * POST_DIV
+ *
+ * XTALIN is a fixed speed clock. Common speeds are 14.31 MHz and 29.50 MHz.
+ * PLL_REF_DIV can be set by the user, but is the same for all clocks.
+ * FB_DIV can be set by the user for each clock individually, it should be set
+ * between 128 and 255, the chip will generate a bad clock signal for too low
+ * values.
+ * x depends on the type of clock; usually it is 2, but for the MCLK it can also
+ * be set to 4.
+ * POST_DIV can be set by the user for each clock individually, Possible values
+ * are 1,2,4,8 and for some clocks other values are available too.
+ * CLK is of course the clock speed that is generated.
+ *
+ * The Mach64 has these clocks:
+ *
+ * MCLK                        The clock rate of the chip
+ * XCLK                        The clock rate of the on-chip memory
+ * VCLK0               First pixel clock of first CRT controller
+ * VCLK1    Second pixel clock of first CRT controller
+ * VCLK2               Third pixel clock of first CRT controller
+ * VCLK3    Fourth pixel clock of first CRT controller
+ * VCLK                        Selected pixel clock, one of VCLK0, VCLK1, VCLK2, VCLK3
+ * V2CLK               Pixel clock of the second CRT controller.
+ * SCLK                        Multi-purpose clock
+ *
+ * - MCLK and XCLK use the same FB_DIV
+ * - VCLK0 .. VCLK3 use the same FB_DIV
+ * - V2CLK is needed when the second CRTC is used (can be used for dualhead);
+ *   i.e. CRT monitor connected to laptop has different resolution than built
+ *   in LCD monitor.
+ * - SCLK is not available on all cards; it is know to exist on the Rage LT-PRO,
+ *   Rage XL and Rage Mobility. It is know not to exist on the Mach64 VT.
+ * - V2CLK is not available on all cards, most likely only the Rage LT-PRO,
+ *   the Rage XL and the Rage Mobility
+ *
+ * SCLK can be used to:
+ * - Clock the chip instead of MCLK
+ * - Replace XTALIN with a user defined frequency
+ * - Generate the pixel clock for the LCD monitor (instead of VCLK)
+ */
+
+ /*
+  * It can be quite hard to calculate XCLK and MCLK if they don't run at the
+  * same frequency. Luckily, until now all cards that need asynchrone clock
+  * speeds seem to have SCLK.
+  * So this driver uses SCLK to clock the chip and XCLK to clock the memory.
+  */
 
 /* ------------------------------------------------------------------------- */
 
-    /*
-     *  PLL programming (Mach64 CT family)
-     */
+/*
+ *  PLL programming (Mach64 CT family)
+ *
+ *
+ * This procedure sets the display fifo. The display fifo is a buffer that
+ * contains data read from the video memory that waits to be processed by
+ * the CRT controller.
+ *
+ * On the more modern Mach64 variants, the chip doesn't calculate the
+ * interval after which the display fifo has to be reloaded from memory
+ * automatically, the driver has to do it instead.
+ */
+
+#define Maximum_DSP_PRECISION 7
+static u8 postdividers[] = {1,2,4,8,3};
 
-static int aty_dsp_gt(const struct fb_info *info, u8 bpp,
-                     struct pll_ct *pll)
+static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
 {
-       struct atyfb_par *par = (struct atyfb_par *) info->par;
-       u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off,
-           dsp_on;
-       u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
-
-       /* xclocks_per_row<<11 */
-       xclks_per_row =
-           (pll->mclk_fb_div * pll->vclk_post_div_real * 64 << 11) /
-           (pll->vclk_fb_div * pll->mclk_post_div_real * bpp);
-       if (xclks_per_row < (1 << 11))
-               FAIL("Dotclock to high");
-       if (M64_HAS(FIFO_24)) {
-               fifo_size = 24;
-               dsp_loop_latency = 0;
-       } else {
-               fifo_size = 32;
-               dsp_loop_latency = 2;
-       }
-       dsp_precision = 0;
-       y = (xclks_per_row * fifo_size) >> 11;
-       while (y) {
-               y >>= 1;
-               dsp_precision++;
-       }
-       dsp_precision -= 5;
-       /* fifo_off<<6 */
-       fifo_off = ((xclks_per_row * (fifo_size - 1)) >> 5) + (3 << 6);
-
-       if (info->fix.smem_len > 1 * 1024 * 1024) {
-               if (par->ram_type >= SDRAM) {
-                       /* >1 MB SDRAM */
-                       dsp_loop_latency += 8;
-                       page_size = 8;
-               } else {
-                       /* >1 MB DRAM */
-                       dsp_loop_latency += 6;
-                       page_size = 9;
-               }
-       } else {
-               if (par->ram_type >= SDRAM) {
-                       /* <2 MB SDRAM */
-                       dsp_loop_latency += 9;
-                       page_size = 10;
-               } else {
-                       /* <2 MB DRAM */
-                       dsp_loop_latency += 8;
-                       page_size = 10;
-               }
-       }
-       /* fifo_on<<6 */
-       if (xclks_per_row >= (page_size << 11))
-               fifo_on =
-                   ((2 * page_size + 1) << 6) + (xclks_per_row >> 5);
-       else
-               fifo_on = (3 * page_size + 2) << 6;
+       u32 dsp_off, dsp_on, dsp_xclks;
+       u32 multiplier, divider, ras_multiplier, ras_divider, tmp;
+       u8 vshift, xshift;
+       s8 dsp_precision;
 
-       dsp_xclks_per_row = xclks_per_row >> dsp_precision;
-       dsp_on = fifo_on >> dsp_precision;
-       dsp_off = fifo_off >> dsp_precision;
+       multiplier = ((u32)pll->mclk_fb_div) * pll->vclk_post_div_real;
+       divider = ((u32)pll->vclk_fb_div) * pll->xclk_ref_div;
 
-       pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
-           ((dsp_loop_latency & 0xf) << 16) | ((dsp_precision & 7) << 20);
-       pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff) << 16);
-       return 0;
-}
+       ras_multiplier = pll->xclkmaxrasdelay;
+       ras_divider = 1;
 
-static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per,
-                           struct pll_ct *pll)
-{
-       struct atyfb_par *par = (struct atyfb_par *) info->par;
-       u32 q, x;               /* x is a workaround for sparc64-linux-gcc */
-       x = x;                  /* x is a workaround for sparc64-linux-gcc */
+       if (bpp>=8)
+               divider = divider * (bpp >> 2);
 
-       pll->pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per;
+       vshift = (6 - 2) - pll->xclk_post_div;  /* FIFO is 64 bits wide in accelerator mode ... */
 
-       /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
-       q = par->ref_clk_per * pll->pll_ref_div * 4 / par->mclk_per;    /* actually 8*q */
-       if (q < 16 * 8 || q > 255 * 8)
-               FAIL("mclk out of range");
-       else if (q < 32 * 8)
-               pll->mclk_post_div_real = 8;
-       else if (q < 64 * 8)
-               pll->mclk_post_div_real = 4;
-       else if (q < 128 * 8)
-               pll->mclk_post_div_real = 2;
-       else
-               pll->mclk_post_div_real = 1;
-       pll->mclk_fb_div = q * pll->mclk_post_div_real / 8;
+       if (bpp == 0)
+               vshift--;       /* ... but only 32 bits in VGA mode. */
 
-       /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
-       q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per; /* actually 8*q */
-       if (q < 16 * 8 || q > 255 * 8)
-               FAIL("vclk out of range");
-       else if (q < 32 * 8)
-               pll->vclk_post_div_real = 8;
-       else if (q < 64 * 8)
-               pll->vclk_post_div_real = 4;
-       else if (q < 128 * 8)
-               pll->vclk_post_div_real = 2;
-       else
-               pll->vclk_post_div_real = 1;
-       pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
-       return 0;
-}
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+       if (pll->xres != 0) {
+               struct atyfb_par *par = (struct atyfb_par *) info->par;
 
-void aty_calc_pll_ct(const struct fb_info *info, struct pll_ct *pll)
-{
-       struct atyfb_par *par = (struct atyfb_par *) info->par;
-       u8 mpostdiv = 0;
-       u8 vpostdiv = 0;
+               multiplier = multiplier * par->lcd_width;
+               divider = divider * pll->xres & ~7;
 
-       if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
-               pll->pll_gen_cntl = 0x04;
-       else
-               pll->pll_gen_cntl = 0x84;
+               ras_multiplier = ras_multiplier * par->lcd_width;
+               ras_divider = ras_divider * pll->xres & ~7;
+       }
+#endif
+       /* If we don't do this, 32 bits for multiplier & divider won't be
+       enough in certain situations! */
+       while (((multiplier | divider) & 1) == 0) {
+               multiplier = multiplier >> 1;
+               divider = divider >> 1;
+       }
 
-       switch (pll->mclk_post_div_real) {
-       case 1:
-               mpostdiv = 0;
-               break;
-       case 2:
-               mpostdiv = 1;
-               break;
-       case 3:
-               mpostdiv = 4;
-               break;
-       case 4:
-               mpostdiv = 2;
-               break;
-       case 8:
-               mpostdiv = 3;
-               break;
+       /* Determine DSP precision first */
+       tmp = ((multiplier * pll->fifo_size) << vshift) / divider;
+
+       for (dsp_precision = -5;  tmp;  dsp_precision++)
+               tmp >>= 1;
+       if (dsp_precision < 0)
+               dsp_precision = 0;
+       else if (dsp_precision > Maximum_DSP_PRECISION)
+               dsp_precision = Maximum_DSP_PRECISION;
+
+       xshift = 6 - dsp_precision;
+       vshift += xshift;
+
+       /* Move on to dsp_off */
+       dsp_off = ((multiplier * (pll->fifo_size - 1)) << vshift) / divider -
+               (1 << (vshift - xshift));
+
+/*    if (bpp == 0)
+        dsp_on = ((multiplier * 20 << vshift) + divider) / divider;
+    else */
+       {
+               dsp_on = ((multiplier << vshift) + divider) / divider;
+               tmp = ((ras_multiplier << xshift) + ras_divider) / ras_divider;
+               if (dsp_on < tmp)
+               dsp_on = tmp;
+               dsp_on = dsp_on + (tmp * 2) + (pll->xclkpagefaultdelay << xshift);
        }
-       pll->pll_gen_cntl |= mpostdiv << 4;     /* mclk */
 
-       if (M64_HAS(MAGIC_POSTDIV))
-               pll->pll_ext_cntl = 0;
-       else
-               pll->pll_ext_cntl = mpostdiv;   /* xclk == mclk */
+       /* Calculate rounding factor and apply it to dsp_on */
+       tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1;
+       dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1);
 
-       switch (pll->vclk_post_div_real) {
-       case 2:
-               vpostdiv = 1;
-               break;
-       case 3:
-               pll->pll_ext_cntl |= 0x10;
-       case 1:
-               vpostdiv = 0;
-               break;
-       case 6:
-               pll->pll_ext_cntl |= 0x10;
-       case 4:
-               vpostdiv = 2;
-               break;
-       case 12:
-               pll->pll_ext_cntl |= 0x10;
-       case 8:
-               vpostdiv = 3;
-               break;
+       if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1))) {
+               dsp_on = dsp_off - (multiplier << vshift) / divider;
+               dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1);
        }
 
-       pll->pll_vclk_cntl = 0x03;      /* VCLK = PLL_VCLK/VCLKx_POST */
-       pll->vclk_post_div = vpostdiv;
+       /* Last but not least:  dsp_xclks */
+       dsp_xclks = ((multiplier << (vshift + 5)) + divider) / divider;
+
+       /* Get register values. */
+       pll->dsp_on_off = (dsp_on << 16) + dsp_off;
+       pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks;
+#ifdef DEBUG
+       printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n",
+               __FUNCTION__, pll->dsp_config, pll->dsp_on_off);
+#endif
+       return 0;
+}
+
+static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll_ct *pll)
+{
+       u32 q;
+       struct atyfb_par *par = (struct atyfb_par *) info->par;
+#ifdef DEBUG
+       int pllvclk;
+#endif
+
+       /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
+       q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per;
+       if (q < 16*8 || q > 255*8) {
+               printk(KERN_CRIT "atyfb: vclk out of range\n");
+               return -EINVAL;
+       } else {
+               pll->vclk_post_div  = (q < 128*8);
+               pll->vclk_post_div += (q <  64*8);
+               pll->vclk_post_div += (q <  32*8);
+       }
+       pll->vclk_post_div_real = postdividers[pll->vclk_post_div];
+       //    pll->vclk_post_div <<= 6;
+       pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
+#ifdef DEBUG
+       pllvclk = (1000000 * 2 * pll->vclk_fb_div) /
+               (par->ref_clk_per * pll->pll_ref_div);
+       printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n",
+               __FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real);
+#endif
+       pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
+       return 0;
 }
 
-static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per,
-                            u8 bpp, union aty_pll *pll)
+static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
        int err;
@@ -220,47 +242,360 @@ static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per,
                return err;
        if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
                return err;
-       aty_calc_pll_ct(info, &pll->ct);
+       /*aty_calc_pll_ct(info, &pll->ct);*/
        return 0;
 }
 
-static u32 aty_pll_ct_to_var(const struct fb_info *info,
-                            const union aty_pll *pll)
+static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
-
-       u32 ref_clk_per = par->ref_clk_per;
-       u8 pll_ref_div = pll->ct.pll_ref_div;
-       u8 vclk_fb_div = pll->ct.vclk_fb_div;
-       u8 vclk_post_div = pll->ct.vclk_post_div_real;
-
-       return ref_clk_per * pll_ref_div * vclk_post_div / vclk_fb_div / 2;
+       u32 ret;
+       ret = par->ref_clk_per * pll->ct.pll_ref_div * pll->ct.vclk_post_div_real / pll->ct.vclk_fb_div / 2;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+       if(pll->ct.xres > 0) {
+               ret *= par->lcd_width;
+               ret /= pll->ct.xres;
+       }
+#endif
+#ifdef DEBUG
+       printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret);
+#endif
+       return ret;
 }
 
-void aty_set_pll_ct(const struct fb_info *info,
-                   const union aty_pll *pll)
+void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
+       u32 crtc_gen_cntl, lcd_gen_cntrl;
+       u8 tmp, tmp2;
+
+       lcd_gen_cntrl = 0;
+#ifdef DEBUG
+       printk("atyfb(%s): about to program:\n"
+               "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n",
+               __FUNCTION__,
+               pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl);
+
+       printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n",
+               __FUNCTION__,
+               par->clk_wr_offset, pll->ct.vclk_fb_div,
+               pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real);
+#endif
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+       if (par->lcd_table != 0) {
+               /* turn off LCD */
+               lcd_gen_cntrl = aty_ld_lcd(LCD_GEN_CNTL, par);
+               aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl & ~LCD_ON, par);
+       }
+#endif
+       aty_st_8(CLOCK_CNTL, par->clk_wr_offset | CLOCK_STROBE, par);
+
+       /* Temporarily switch to accelerator mode */
+       crtc_gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
+       if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
+               aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN, par);
+
+       /* Reset VCLK generator */
+       aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
+
+       /* Set post-divider */
+       tmp2 = par->clk_wr_offset << 1;
+       tmp = aty_ld_pll_ct(VCLK_POST_DIV, par);
+       tmp &= ~(0x03U << tmp2);
+       tmp |= ((pll->ct.vclk_post_div & 0x03U) << tmp2);
+       aty_st_pll_ct(VCLK_POST_DIV, tmp, par);
+
+       /* Set extended post-divider */
+       tmp = aty_ld_pll_ct(PLL_EXT_CNTL, par);
+       tmp &= ~(0x10U << par->clk_wr_offset);
+       tmp &= 0xF0U;
+       tmp |= pll->ct.pll_ext_cntl;
+       aty_st_pll_ct(PLL_EXT_CNTL, tmp, par);
 
-       aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, par);
-       aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
-       aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
-       aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
-       aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, par);
-       aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, par);
-       aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
+       /* Set feedback divider */
+       tmp = VCLK0_FB_DIV + par->clk_wr_offset;
+       aty_st_pll_ct(tmp, (pll->ct.vclk_fb_div & 0xFFU), par);
+
+       aty_st_pll_ct(PLL_GEN_CNTL, (pll->ct.pll_gen_cntl & (~(PLL_OVERRIDE | PLL_MCLK_RST))) | OSC_EN, par);
+
+       /* End VCLK generator reset */
+       aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl & ~(PLL_VCLK_RST), par);
+       mdelay(5);
+
+       aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
+       aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
+       mdelay(1);
+
+       /* Restore mode register */
+       if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
+               aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl, par);
 
        if (M64_HAS(GTB_DSP)) {
+               u8 dll_cntl;
+
                if (M64_HAS(XL_DLL))
-                       aty_st_pll(DLL_CNTL, 0x80, par);
+                       dll_cntl = 0x80;
                else if (par->ram_type >= SDRAM)
-                       aty_st_pll(DLL_CNTL, 0xa6, par);
+                       dll_cntl = 0xa6;
                else
-                       aty_st_pll(DLL_CNTL, 0xa0, par);
-               aty_st_pll(VFC_CNTL, 0x1b, par);
+                       dll_cntl = 0xa0;
+               aty_st_pll_ct(DLL_CNTL, dll_cntl, par);
+               aty_st_pll_ct(VFC_CNTL, 0x1b, par);
                aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, par);
                aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, par);
+
+               mdelay(10);
+               aty_st_pll_ct(DLL_CNTL, dll_cntl, par);
+               mdelay(10);
+               aty_st_pll_ct(DLL_CNTL, dll_cntl | 0x40, par);
+               mdelay(10);
+               aty_st_pll_ct(DLL_CNTL, dll_cntl & ~0x40, par);
+       }
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+       if (par->lcd_table != 0) {
+               /* restore LCD */
+               aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl, par);
+       }
+#endif
+}
+
+void __init aty_get_pll_ct(const struct fb_info *info, union aty_pll *pll)
+{
+       struct atyfb_par *par = (struct atyfb_par *) info->par;
+       u8 tmp, clock;
+
+       clock = aty_ld_8(CLOCK_CNTL, par) & 0x03U;
+       tmp = clock << 1;
+       pll->ct.vclk_post_div = (aty_ld_pll_ct(VCLK_POST_DIV, par) >> tmp) & 0x03U;
+
+       pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par) & 0x0FU;
+       pll->ct.vclk_fb_div = aty_ld_pll_ct(VCLK0_FB_DIV + clock, par) & 0xFFU;
+       pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
+       pll->ct.mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
+
+       pll->ct.pll_gen_cntl = aty_ld_pll_ct(PLL_GEN_CNTL, par);
+       pll->ct.pll_vclk_cntl = aty_ld_pll_ct(PLL_VCLK_CNTL, par);
+
+       if (M64_HAS(GTB_DSP)) {
+               pll->ct.dsp_config = aty_ld_le32(DSP_CONFIG, par);
+               pll->ct.dsp_on_off = aty_ld_le32(DSP_ON_OFF, par);
+       }
+}
+
+int __init aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll) {
+       struct atyfb_par *par = (struct atyfb_par *) info->par;
+       u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2;
+       u32 q, i, memcntl, trp;
+       u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off;
+#ifdef DEBUG
+       int pllmclk, pllsclk;
+#endif
+       pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
+       pll->ct.xclk_post_div = pll->ct.pll_ext_cntl & 0x07;
+       pll->ct.xclk_ref_div = 1;
+       switch (pll->ct.xclk_post_div) {
+       case 0:  case 1:  case 2:  case 3:
+               break;
+
+       case 4:
+               pll->ct.xclk_ref_div = 3;
+               pll->ct.xclk_post_div = 0;
+               break;
+
+       default:
+               printk(KERN_CRIT "atyfb: Unsupported xclk source:  %d.\n", pll->ct.xclk_post_div);
+               return -EINVAL;
+       }
+       pll->ct.mclk_fb_mult = 2;
+       if(pll->ct.pll_ext_cntl & PLL_MFB_TIMES_4_2B) {
+               pll->ct.mclk_fb_mult = 4;
+               pll->ct.xclk_post_div -= 1;
+       }
+
+#ifdef DEBUG
+       printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
+               __FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div);
+#endif
+
+       memcntl = aty_ld_le32(MEM_CNTL, par);
+       trp = (memcntl & 0x300) >> 8;
+
+       pll->ct.xclkpagefaultdelay = ((memcntl & 0xc00) >> 10) + ((memcntl & 0x1000) >> 12) + trp + 2;
+       pll->ct.xclkmaxrasdelay = ((memcntl & 0x70000) >> 16) + trp + 2;
+
+       if (M64_HAS(FIFO_32)) {
+               pll->ct.fifo_size = 32;
+       } else {
+               pll->ct.fifo_size = 24;
+               pll->ct.xclkpagefaultdelay += 2;
+               pll->ct.xclkmaxrasdelay += 3;
+       }
+
+       switch (par->ram_type) {
+       case DRAM:
+               if (info->fix.smem_len<=ONE_MB) {
+                       pll->ct.dsp_loop_latency = 10;
+               } else {
+                       pll->ct.dsp_loop_latency = 8;
+                       pll->ct.xclkpagefaultdelay += 2;
+               }
+               break;
+       case EDO:
+       case PSEUDO_EDO:
+               if (info->fix.smem_len<=ONE_MB) {
+                       pll->ct.dsp_loop_latency = 9;
+               } else {
+                       pll->ct.dsp_loop_latency = 8;
+                       pll->ct.xclkpagefaultdelay += 1;
+               }
+               break;
+       case SDRAM:
+               if (info->fix.smem_len<=ONE_MB) {
+                       pll->ct.dsp_loop_latency = 11;
+               } else {
+                       pll->ct.dsp_loop_latency = 10;
+                       pll->ct.xclkpagefaultdelay += 1;
+               }
+               break;
+       case SGRAM:
+               pll->ct.dsp_loop_latency = 8;
+               pll->ct.xclkpagefaultdelay += 3;
+               break;
+       default:
+               pll->ct.dsp_loop_latency = 11;
+               pll->ct.xclkpagefaultdelay += 3;
+               break;
+       }
+
+       if (pll->ct.xclkmaxrasdelay <= pll->ct.xclkpagefaultdelay)
+               pll->ct.xclkmaxrasdelay = pll->ct.xclkpagefaultdelay + 1;
+
+       /* Allow BIOS to override */
+       dsp_config = aty_ld_le32(DSP_CONFIG, par);
+       dsp_on_off = aty_ld_le32(DSP_ON_OFF, par);
+       vga_dsp_config = aty_ld_le32(VGA_DSP_CONFIG, par);
+       vga_dsp_on_off = aty_ld_le32(VGA_DSP_ON_OFF, par);
+
+       if (dsp_config)
+               pll->ct.dsp_loop_latency = (dsp_config & DSP_LOOP_LATENCY) >> 16;
+#if 0
+       FIXME: is it relevant for us?
+       if ((!dsp_on_off && !M64_HAS(RESET_3D)) ||
+               ((dsp_on_off == vga_dsp_on_off) &&
+               (!dsp_config || !((dsp_config ^ vga_dsp_config) & DSP_XCLKS_PER_QW)))) {
+               vga_dsp_on_off &= VGA_DSP_OFF;
+               vga_dsp_config &= VGA_DSP_XCLKS_PER_QW;
+               if (ATIDivide(vga_dsp_on_off, vga_dsp_config, 5, 1) > 24)
+                       pll->ct.fifo_size = 32;
+               else
+                       pll->ct.fifo_size = 24;
+       }
+#endif
+       /* Exit if the user does not want us to tamper with the clock
+       rates of her chip. */
+       if (par->mclk_per == 0) {
+               u8 mclk_fb_div, pll_ext_cntl;
+               pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
+               pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
+               pll->ct.xclk_post_div_real = postdividers[pll_ext_cntl & 0x07];
+               mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
+               if (pll_ext_cntl & PLL_MFB_TIMES_4_2B)
+                       mclk_fb_div <<= 1;
+               pll->ct.mclk_fb_div = mclk_fb_div;
+               return 0;
+       }
+
+       pll->ct.pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per;
+
+       /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
+       q = par->ref_clk_per * pll->ct.pll_ref_div * 8 /
+               (pll->ct.mclk_fb_mult * par->xclk_per);
+
+       if (q < 16*8 || q > 255*8) {
+               printk(KERN_CRIT "atxfb: xclk out of range\n");
+               return -EINVAL;
+       } else {
+               xpost_div  = (q < 128*8);
+               xpost_div += (q <  64*8);
+               xpost_div += (q <  32*8);
+       }
+       pll->ct.xclk_post_div_real = postdividers[xpost_div];
+       pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8;
+
+#ifdef DEBUG
+       pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) /
+                       (par->ref_clk_per * pll->ct.pll_ref_div);
+       printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
+               __FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
+#endif
+
+       if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
+               pll->ct.pll_gen_cntl = OSC_EN;
+       else
+               pll->ct.pll_gen_cntl = OSC_EN | DLL_PWDN /* | FORCE_DCLK_TRI_STATE */;
+
+       if (M64_HAS(MAGIC_POSTDIV))
+               pll->ct.pll_ext_cntl = 0;
+       else
+               pll->ct.pll_ext_cntl = xpost_div;
+
+       if (pll->ct.mclk_fb_mult == 4)
+               pll->ct.pll_ext_cntl |= PLL_MFB_TIMES_4_2B;
+
+       if (par->mclk_per == par->xclk_per) {
+               pll->ct.pll_gen_cntl |= (xpost_div << 4); /* mclk == xclk */
+       } else {
+               /*
+               * The chip clock is not equal to the memory clock.
+               * Therefore we will use sclk to clock the chip.
+               */
+               pll->ct.pll_gen_cntl |= (6 << 4); /* mclk == sclk */
+
+               q = par->ref_clk_per * pll->ct.pll_ref_div * 4 / par->mclk_per;
+               if (q < 16*8 || q > 255*8) {
+                       printk(KERN_CRIT "atyfb: mclk out of range\n");
+                       return -EINVAL;
+               } else {
+                       mpost_div  = (q < 128*8);
+                       mpost_div += (q <  64*8);
+                       mpost_div += (q <  32*8);
+               }
+               sclk_post_div_real = postdividers[mpost_div];
+               sclk_fb_div = q * sclk_post_div_real / 8;
+               spll_cntl2 = mpost_div << 4;
+#ifdef DEBUG
+               pllsclk = (1000000 * 2 * sclk_fb_div) /
+                       (par->ref_clk_per * pll->ct.pll_ref_div);
+               printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
+                       __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real);
+#endif
+               /*
+               * This disables the sclk, crashes the computer as reported:
+               * aty_st_pll_ct(SPLL_CNTL2, 3, info);
+               *
+               * So it seems the sclk must be enabled before it is used;
+               * so PLL_GEN_CNTL must be programmed *after* the sclk.
+               */
+               aty_st_pll_ct(SCLK_FB_DIV, sclk_fb_div, par);
+               aty_st_pll_ct(SPLL_CNTL2, spll_cntl2, par);
+               /*
+                * The sclk has been started. However, I believe the first clock
+                * ticks it generates are not very stable. Hope this primitive loop
+                * helps for Rage Mobilities that sometimes crash when
+                * we switch to sclk. (Daniel Mantione, 13-05-2003)
+                */
+               for (i=0;i<=0x1ffff;i++);
        }
+
+       aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par);
+       aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
+       aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
+       aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
+       /* Disable the extra precision pixel clock controls since we do not use them. */
+       aty_st_pll_ct(EXT_VPLL_CNTL, aty_ld_pll_ct(EXT_VPLL_CNTL, par) &
+               ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC), par);
+
+       return 0;
 }
 
 static int dummy(void)
@@ -274,6 +609,8 @@ const struct aty_dac_ops aty_dac_ct = {
 
 const struct aty_pll_ops aty_pll_ct = {
        .var_to_pll     = aty_var_to_pll_ct,
-       .pll_to_var     = aty_pll_ct_to_var,
+       .pll_to_var     = aty_pll_to_var_ct,
        .set_pll        = aty_set_pll_ct,
+       .get_pll        = aty_get_pll_ct,
+       .init_pll       = aty_init_pll_ct
 };
index 28540cf..01fdff7 100644 (file)
@@ -121,7 +121,7 @@ static int aty_set_dac_514(const struct fb_info *info,
 }
 
 static int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per,
-                             u8 bpp, union aty_pll *pll)
+                             u32 bpp, union aty_pll *pll)
 {
        /*
         *  FIXME: use real calculations instead of using fixed values from the old
@@ -253,9 +253,9 @@ static int aty_set_dac_ATI68860_B(const struct fb_info *info,
        temp = aty_ld_8(DAC_CNTL, par);
        aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
 
-       if (info->fix.smem_len < MEM_SIZE_1M)
+       if (info->fix.smem_len < ONE_MB)
                mask = 0x04;
-       else if (info->fix.smem_len == MEM_SIZE_1M)
+       else if (info->fix.smem_len == ONE_MB)
                mask = 0x08;
        else
                mask = 0x0C;
@@ -339,8 +339,8 @@ const struct aty_dac_ops aty_dac_att21c498 = {
      *  ATI 18818 / ICS 2595 Clock Chip
      */
 
-static int aty_var_to_pll_18818(const struct fb_info *info,
-                               u32 vclk_per, u8 bpp, union aty_pll *pll)
+static int aty_var_to_pll_18818(const struct fb_info *info, u32 vclk_per,
+                               u32 bpp, union aty_pll *pll)
 {
        u32 MHz100;             /* in 0.01 MHz */
        u32 program_bits;
@@ -495,8 +495,8 @@ const struct aty_pll_ops aty_pll_ati18818_1 = {
      *  STG 1703 Clock Chip
      */
 
-static int aty_var_to_pll_1703(const struct fb_info *info,
-                              u32 vclk_per, u8 bpp, union aty_pll *pll)
+static int aty_var_to_pll_1703(const struct fb_info *info, u32 vclk_per,
+                              u32 bpp, union aty_pll *pll)
 {
        u32 mhz100;             /* in 0.01 MHz */
        u32 program_bits;
@@ -611,8 +611,8 @@ const struct aty_pll_ops aty_pll_stg1703 = {
      *  Chrontel 8398 Clock Chip
      */
 
-static int aty_var_to_pll_8398(const struct fb_info *info,
-                              u32 vclk_per, u8 bpp, union aty_pll *pll)
+static int aty_var_to_pll_8398(const struct fb_info *info, u32 vclk_per,
+                              u32 bpp, union aty_pll *pll)
 {
        u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
 
@@ -736,7 +736,7 @@ const struct aty_pll_ops aty_pll_ch8398 = {
      */
 
 static int aty_var_to_pll_408(const struct fb_info *info, u32 vclk_per,
-                             u8 bpp, union aty_pll *pll)
+                             u32 bpp, union aty_pll *pll)
 {
        u32 mhz100;             /* in 0.01 MHz */
        u32 program_bits;
index 737e9b6..3b841c5 100644 (file)
@@ -148,15 +148,15 @@ static void reset_sdram(struct atyfb_par *par)
 static void init_dll(struct atyfb_par *par)
 {
        // enable DLL
-       aty_st_pll(PLL_GEN_CNTL,
-                  aty_ld_pll(PLL_GEN_CNTL, par) & 0x7f,
+       aty_st_pll_ct(PLL_GEN_CNTL,
+                  aty_ld_pll_ct(PLL_GEN_CNTL, par) & 0x7f,
                   par);
 
        // reset DLL
-       aty_st_pll(DLL_CNTL, 0x82, par);
-       aty_st_pll(DLL_CNTL, 0xE2, par);
+       aty_st_pll_ct(DLL_CNTL, 0x82, par);
+       aty_st_pll_ct(DLL_CNTL, 0xE2, par);
        mdelay(5);
-       aty_st_pll(DLL_CNTL, 0x82, par);
+       aty_st_pll_ct(DLL_CNTL, 0x82, par);
        mdelay(6);
 }
 
@@ -164,8 +164,8 @@ static void reset_clocks(struct atyfb_par *par, struct pll_ct *pll,
                         int hsync_enb)
 {
        reset_gui(par);
-       aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, par);
-       aty_st_pll(SCLK_FB_DIV, pll->sclk_fb_div, par);
+       aty_st_pll_ct(MCLK_FB_DIV, pll->mclk_fb_div, par);
+       aty_st_pll_ct(SCLK_FB_DIV, pll->sclk_fb_div, par);
 
        mdelay(15);
        init_dll(par);
@@ -177,9 +177,9 @@ static void reset_clocks(struct atyfb_par *par, struct pll_ct *pll,
        aty_st_8(CRTC_GEN_CNTL+3,
                 hsync_enb ? 0x00 : 0x04, par);
 
-       aty_st_pll(SPLL_CNTL2, pll->spll_cntl2, par);
-       aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, par);
-       aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, par);
+       aty_st_pll_ct(SPLL_CNTL2, pll->spll_cntl2, par);
+       aty_st_pll_ct(PLL_GEN_CNTL, pll->pll_gen_cntl, par);
+       aty_st_pll_ct(PLL_VCLK_CNTL, pll->pll_vclk_cntl, par);
 }
 
 int atyfb_xl_init(struct fb_info *info)
@@ -216,31 +216,31 @@ int atyfb_xl_init(struct fb_info *info)
        if ((err = aty_pll_ct.var_to_pll(info, 39726, 8, &pll)))
                return err;
 
-       aty_st_pll(LVDS_CNTL0, 0x00, par);
-       aty_st_pll(DLL2_CNTL, card->dll2_cntl, par);
-       aty_st_pll(V2PLL_CNTL, 0x10, par);
-       aty_st_pll(MPLL_CNTL, MPLL_GAIN, par);
-       aty_st_pll(VPLL_CNTL, VPLL_GAIN, par);
-       aty_st_pll(PLL_VCLK_CNTL, 0x00, par);
-       aty_st_pll(VFC_CNTL, 0x1B, par);
-       aty_st_pll(PLL_REF_DIV, pll.ct.pll_ref_div, par);
-       aty_st_pll(PLL_EXT_CNTL, pll.ct.pll_ext_cntl, par);
-       aty_st_pll(SPLL_CNTL2, 0x03, par);
-       aty_st_pll(PLL_GEN_CNTL, 0x44, par);
+       aty_st_pll_ct(LVDS_CNTL0, 0x00, par);
+       aty_st_pll_ct(DLL2_CNTL, card->dll2_cntl, par);
+       aty_st_pll_ct(V2PLL_CNTL, 0x10, par);
+       aty_st_pll_ct(MPLL_CNTL, MPLL_GAIN, par);
+       aty_st_pll_ct(VPLL_CNTL, VPLL_GAIN, par);
+       aty_st_pll_ct(PLL_VCLK_CNTL, 0x00, par);
+       aty_st_pll_ct(VFC_CNTL, 0x1B, par);
+       aty_st_pll_ct(PLL_REF_DIV, pll.ct.pll_ref_div, par);
+       aty_st_pll_ct(PLL_EXT_CNTL, pll.ct.pll_ext_cntl, par);
+       aty_st_pll_ct(SPLL_CNTL2, 0x03, par);
+       aty_st_pll_ct(PLL_GEN_CNTL, 0x44, par);
 
        reset_clocks(par, &pll.ct, 0);
        mdelay(10);
 
-       aty_st_pll(VCLK_POST_DIV, 0x03, par);
-       aty_st_pll(VCLK0_FB_DIV, 0xDA, par);
-       aty_st_pll(VCLK_POST_DIV, 0x0F, par);
-       aty_st_pll(VCLK1_FB_DIV, 0xF5, par);
-       aty_st_pll(VCLK_POST_DIV, 0x3F, par);
-       aty_st_pll(PLL_EXT_CNTL, 0x40 | pll.ct.pll_ext_cntl, par);
-       aty_st_pll(VCLK2_FB_DIV, 0x00, par);
-       aty_st_pll(VCLK_POST_DIV, 0xFF, par);
-       aty_st_pll(PLL_EXT_CNTL, 0xC0 | pll.ct.pll_ext_cntl, par);
-       aty_st_pll(VCLK3_FB_DIV, 0x00, par);
+       aty_st_pll_ct(VCLK_POST_DIV, 0x03, par);
+       aty_st_pll_ct(VCLK0_FB_DIV, 0xDA, par);
+       aty_st_pll_ct(VCLK_POST_DIV, 0x0F, par);
+       aty_st_pll_ct(VCLK1_FB_DIV, 0xF5, par);
+       aty_st_pll_ct(VCLK_POST_DIV, 0x3F, par);
+       aty_st_pll_ct(PLL_EXT_CNTL, 0x40 | pll.ct.pll_ext_cntl, par);
+       aty_st_pll_ct(VCLK2_FB_DIV, 0x00, par);
+       aty_st_pll_ct(VCLK_POST_DIV, 0xFF, par);
+       aty_st_pll_ct(PLL_EXT_CNTL, 0xC0 | pll.ct.pll_ext_cntl, par);
+       aty_st_pll_ct(VCLK3_FB_DIV, 0x00, par);
 
        aty_st_8(BUS_CNTL, 0x01, par);
        aty_st_le32(BUS_CNTL, card->bus_cntl | 0x08000000, par);
@@ -295,7 +295,7 @@ int atyfb_xl_init(struct fb_info *info)
        aty_st_8(CRTC_GEN_CNTL+3, 0x04, par);
        mdelay(10);
 
-       aty_st_pll(PLL_YCLK_CNTL, 0x25, par);
+       aty_st_pll_ct(PLL_YCLK_CNTL, 0x25, par);
 
        aty_st_le16(CUSTOM_MACRO_CNTL, 0x0179, par);
        aty_st_le16(CUSTOM_MACRO_CNTL+2, 0x005E, par);
@@ -309,9 +309,9 @@ int atyfb_xl_init(struct fb_info *info)
 
        aty_st_8(CONFIG_STAT0, 0xA0 | card->mem_type, par);
 
-       aty_st_pll(PLL_YCLK_CNTL, 0x01, par);
+       aty_st_pll_ct(PLL_YCLK_CNTL, 0x01, par);
        mdelay(15);
-       aty_st_pll(PLL_YCLK_CNTL, card->pll_yclk_cntl, par);
+       aty_st_pll_ct(PLL_YCLK_CNTL, card->pll_yclk_cntl, par);
        mdelay(1);
        
        reset_clocks(par, &pll.ct, 0);
index 65b65ad..3d20b2d 100644 (file)
@@ -110,7 +110,7 @@ struct bw2_regs {
 
 struct bw2_par {
        spinlock_t              lock;
-       struct bw2_regs         *regs;
+       struct bw2_regs         __iomem *regs;
 
        u32                     flags;
 #define BW2_FLAG_BLANKED       0x00000001
@@ -131,24 +131,24 @@ static int
 bw2_blank(int blank, struct fb_info *info)
 {
        struct bw2_par *par = (struct bw2_par *) info->par;
-       struct bw2_regs *regs = par->regs;
+       struct bw2_regs __iomem *regs = par->regs;
        unsigned long flags;
        u8 val;
 
        spin_lock_irqsave(&par->lock, flags);
 
        switch (blank) {
-       case 0: /* Unblanking */
+       case FB_BLANK_UNBLANK: /* Unblanking */
                val = sbus_readb(&regs->control);
                val |= BWTWO_CTL_ENABLE_VIDEO;
                sbus_writeb(val, &regs->control);
                par->flags &= ~BW2_FLAG_BLANKED;
                break;
 
-       case 1: /* Normal blanking */
-       case 2: /* VESA blank (vsync off) */
-       case 3: /* VESA blank (hsync off) */
-       case 4: /* Poweroff */
+       case FB_BLANK_NORMAL: /* Normal blanking */
+       case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+       case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+       case FB_BLANK_POWERDOWN: /* Poweroff */
                val = sbus_readb(&regs->control);
                val &= ~BWTWO_CTL_ENABLE_VIDEO;
                sbus_writeb(val, &regs->control);
@@ -281,7 +281,7 @@ static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
                prom_halt();
        }
        for ( ; *p; p += 2) {
-               u8 *regp = &((u8 *)par->regs)[p[0]];
+               u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
                sbus_writeb(p[1], regp);
        }
 }
@@ -342,8 +342,7 @@ static void bw2_init_one(struct sbus_dev *sdev)
        all->info.var.red.offset = all->info.var.green.offset =
                all->info.var.blue.offset = 0;
 
-       all->par.regs = (struct bw2_regs *)
-               sbus_ioremap(resp, BWTWO_REGISTER_OFFSET,
+       all->par.regs = sbus_ioremap(resp, BWTWO_REGISTER_OFFSET,
                             sizeof(struct bw2_regs), "bw2 regs");
 
        if (sdev && !prom_getbool(sdev->prom_node, "width"))
@@ -355,13 +354,12 @@ static void bw2_init_one(struct sbus_dev *sdev)
        all->info.fbops = &bw2_ops;
 #if defined(CONFIG_SPARC32)
        if (sdev)
-               all->info.screen_base = (char *)
+               all->info.screen_base = (char __iomem *)
                        prom_getintdefault(sdev->prom_node, "address", 0);
 #endif
        if (!all->info.screen_base)
-               all->info.screen_base = (char *)
+               all->info.screen_base =
                        sbus_ioremap(resp, 0, all->par.fbsize, "bw2 ram");
-       all->info.currcon = -1;
        all->info.par = &all->par;
 
        bw2_blank(0, &all->info);
@@ -386,7 +384,7 @@ int __init bw2_init(void)
        struct sbus_bus *sbus;
        struct sbus_dev *sdev;
 
-       if (fb_get_options("bw2fb", &option))
+       if (fb_get_options("bw2fb", NULL))
                return -ENODEV;
 
 #ifdef CONFIG_SUN4
index c43322b..efabb1b 100644 (file)
@@ -188,9 +188,9 @@ struct cg14_clut {
 
 struct cg14_par {
        spinlock_t              lock;
-       struct cg14_regs        *regs;
-       struct cg14_clut        *clut;
-       struct cg14_cursor      *cursor;
+       struct cg14_regs        __iomem *regs;
+       struct cg14_clut        __iomem *clut;
+       struct cg14_cursor      __iomem *cursor;
 
        u32                     flags;
 #define CG14_FLAG_BLANKED      0x00000001
@@ -209,7 +209,7 @@ struct cg14_par {
 
 static void __cg14_reset(struct cg14_par *par)
 {
-       struct cg14_regs *regs = par->regs;
+       struct cg14_regs __iomem *regs = par->regs;
        u8 val;
 
        val = sbus_readb(&regs->mcr);
@@ -248,13 +248,16 @@ static int cg14_setcolreg(unsigned regno,
                          unsigned transp, struct fb_info *info)
 {
        struct cg14_par *par = (struct cg14_par *) info->par;
-       struct cg14_clut *clut = par->clut;
+       struct cg14_clut __iomem *clut = par->clut;
        unsigned long flags;
        u32 val;
 
        if (regno >= 256)
                return 1;
 
+       red >>= 8;
+       green >>= 8;
+       blue >>= 8;
        val = (red | (green << 8) | (blue << 16));
 
        spin_lock_irqsave(&par->lock, flags);
@@ -277,7 +280,7 @@ static int cg14_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                      unsigned long arg, struct fb_info *info)
 {
        struct cg14_par *par = (struct cg14_par *) info->par;
-       struct cg14_regs *regs = par->regs;
+       struct cg14_regs __iomem *regs = par->regs;
        struct mdi_cfginfo kmdi, __user *mdii;
        unsigned long flags;
        int cur_mode, mode, ret = 0;
@@ -322,7 +325,8 @@ static int cg14_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        break;
 
                case MDI_16_PIX:
-                       cur_mode |= 0x20;
+                       cur_mode |= (CG14_MCR_PIXMODE_16 <<
+                                    CG14_MCR_PIXMODE_SHIFT);
                        break;
 
                case MDI_8_PIX:
@@ -341,7 +345,7 @@ static int cg14_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
        default:
                ret = sbusfb_ioctl_helper(cmd, arg, info,
-                                         FBTYPE_MDICOLOR, 24, par->fbsize);
+                                         FBTYPE_MDICOLOR, 8, par->fbsize);
                break;
        };
 
@@ -355,11 +359,16 @@ static int cg14_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 static void cg14_init_fix(struct fb_info *info, int linebytes)
 {
        struct cg14_par *par = (struct cg14_par *)info->par;
+       const char *name;
+
+       name = "cgfourteen";
+       if (par->sdev)
+               name = par->sdev->prom_name;
 
-       strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id));
+       strlcpy(info->fix.id, name, sizeof(info->fix.id));
 
        info->fix.type = FB_TYPE_PACKED_PIXELS;
-       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 
        info->fix.line_length = linebytes;
 
@@ -484,8 +493,11 @@ static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node)
        spin_lock_init(&all->par.lock);
 
        sbusfb_fill_var(&all->info.var, node, 8);
+       all->info.var.red.length = 8;
+       all->info.var.green.length = 8;
+       all->info.var.blue.length = 8;
 
-       linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+       linebytes = prom_getintdefault(node, "linebytes",
                                       all->info.var.xres);
        all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
 
@@ -495,33 +507,29 @@ static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node)
                all->par.physbase = phys = sdev->reg_addrs[1].phys_addr;
                all->par.iospace = sdev->reg_addrs[0].which_io;
 
-               all->par.regs = (struct cg14_regs *)
-                       sbus_ioremap(&sdev->resource[0], 0,
+               all->par.regs = sbus_ioremap(&sdev->resource[0], 0,
                                     sizeof(struct cg14_regs),
                                     "cg14 regs");
-               all->par.clut = (struct cg14_clut *)
-                       sbus_ioremap(&sdev->resource[0], CG14_CLUT1,
+               all->par.clut = sbus_ioremap(&sdev->resource[0], CG14_CLUT1,
                                     sizeof(struct cg14_clut),
                                     "cg14 clut");
-               all->par.cursor = (struct cg14_cursor *)
-                       sbus_ioremap(&sdev->resource[0], CG14_CURSORREGS,
+               all->par.cursor = sbus_ioremap(&sdev->resource[0], CG14_CURSORREGS,
                                     sizeof(struct cg14_cursor),
                                     "cg14 cursor");
-               all->info.screen_base = (char *)
-                       sbus_ioremap(&sdev->resource[1], 0,
+               all->info.screen_base = sbus_ioremap(&sdev->resource[1], 0,
                                     all->par.fbsize, "cg14 ram");
        } else {
                rphys = __get_phys(bases[0]);
                all->par.physbase = phys = __get_phys(bases[1]);
                all->par.iospace = __get_iospace(bases[0]);
-               all->par.regs = (struct cg14_regs *)(unsigned long)bases[0];
-               all->par.clut = (struct cg14_clut *)((unsigned long)bases[0] +
+               all->par.regs = (struct cg14_regs __iomem *)(unsigned long)bases[0];
+               all->par.clut = (struct cg14_clut __iomem *)((unsigned long)bases[0] +
                                                     CG14_CLUT1);
                all->par.cursor =
-                       (struct cg14_cursor *)((unsigned long)bases[0] +
+                       (struct cg14_cursor __iomem *)((unsigned long)bases[0] +
                                               CG14_CURSORREGS);
 
-               all->info.screen_base = (char *)(unsigned long)bases[1];
+               all->info.screen_base = (char __iomem *)(unsigned long)bases[1];
        }
 
        prom_getproperty(node, "reg", (char *) &bases[0], sizeof(bases));
@@ -552,7 +560,6 @@ static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node)
 
        all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
        all->info.fbops = &cg14_ops;
-       all->info.currcon = -1;
        all->info.par = &all->par;
 
        __cg14_reset(&all->par);
@@ -562,6 +569,7 @@ static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node)
                kfree(all);
                return;
        }
+       fb_set_cmap(&all->info.cmap, &all->info);
 
        cg14_init_fix(&all->info, linebytes);
 
@@ -574,8 +582,8 @@ static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node)
 
        list_add(&all->list, &cg14_list);
 
-       printk("cg14: cgfourteen at %lx:%lx\n",
-              all->par.physbase, all->par.iospace);
+       printk("cg14: cgfourteen at %lx:%lx, %dMB\n",
+              all->par.iospace, all->par.physbase, all->par.ramsize >> 20);
 
 }
 
index 0783941..bd97a84 100644 (file)
@@ -111,7 +111,7 @@ struct cg3_regs {
 
 struct cg3_par {
        spinlock_t              lock;
-       struct cg3_regs         *regs;
+       struct cg3_regs         __iomem *regs;
        u32                     sw_cmap[((256 * 3) + 3) / 4];
 
        u32                     flags;
@@ -144,7 +144,7 @@ static int cg3_setcolreg(unsigned regno,
                         unsigned transp, struct fb_info *info)
 {
        struct cg3_par *par = (struct cg3_par *) info->par;
-       struct bt_regs *bt = &par->regs->cmap;
+       struct bt_regs __iomem *bt = &par->regs->cmap;
        unsigned long flags;
        u32 *p32;
        u8 *p8;
@@ -190,27 +190,27 @@ static int
 cg3_blank(int blank, struct fb_info *info)
 {
        struct cg3_par *par = (struct cg3_par *) info->par;
-       struct cg3_regs *regs = par->regs;
+       struct cg3_regs __iomem *regs = par->regs;
        unsigned long flags;
        u8 val;
 
        spin_lock_irqsave(&par->lock, flags);
 
        switch (blank) {
-       case 0: /* Unblanking */
-               val = sbus_readl(&regs->control);
+       case FB_BLANK_UNBLANK: /* Unblanking */
+               val = sbus_readb(&regs->control);
                val |= CG3_CR_ENABLE_VIDEO;
-               sbus_writel(val, &regs->control);
+               sbus_writeb(val, &regs->control);
                par->flags &= ~CG3_FLAG_BLANKED;
                break;
 
-       case 1: /* Normal blanking */
-       case 2: /* VESA blank (vsync off) */
-       case 3: /* VESA blank (hsync off) */
-       case 4: /* Poweroff */
-               val = sbus_readl(&regs->control);
+       case FB_BLANK_NORMAL: /* Normal blanking */
+       case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+       case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+       case FB_BLANK_POWERDOWN: /* Poweroff */
+               val = sbus_readb(&regs->control);
                val |= CG3_CR_ENABLE_VIDEO;
-               sbus_writel(val, &regs->control);
+               sbus_writeb(val, &regs->control);
                par->flags |= CG3_FLAG_BLANKED;
                break;
        }
@@ -345,15 +345,15 @@ static void cg3_do_default_mode(struct cg3_par *par)
        }
 
        for (p = cg3_regvals[type]; *p; p += 2) {
-               u8 *regp = &((u8 *)par->regs)[p[0]];
+               u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
                sbus_writeb(p[1], regp);
        }
        for (p = cg3_dacvals; *p; p += 2) {
-               volatile u8 *regp;
+               volatile u8 __iomem *regp;
 
-               regp = (volatile u8 *)&par->regs->cmap.addr;
+               regp = (volatile u8 __iomem *)&par->regs->cmap.addr;
                sbus_writeb(p[0], regp);
-               regp = (volatile u8 *)&par->regs->cmap.control;
+               regp = (volatile u8 __iomem *)&par->regs->cmap.control;
                sbus_writeb(p[1], regp);
        }
 }
@@ -394,21 +394,19 @@ static void cg3_init_one(struct sbus_dev *sdev)
                                       all->info.var.xres);
        all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
 
-       all->par.regs = (struct cg3_regs *)
-               sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET,
+       all->par.regs = sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET,
                             sizeof(struct cg3_regs), "cg3 regs");
 
        all->info.flags = FBINFO_DEFAULT;
        all->info.fbops = &cg3_ops;
 #ifdef CONFIG_SPARC32
-       all->info.screen_base = (char *)
+       all->info.screen_base = (char __iomem *)
                prom_getintdefault(sdev->prom_node, "address", 0);
 #endif
        if (!all->info.screen_base)
-               all->info.screen_base = (char *)
+               all->info.screen_base =
                        sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET,
                                     all->par.fbsize, "cg3 ram");
-       all->info.currcon = -1;
        all->info.par = &all->par;
 
        cg3_blank(0, &all->info);
index be87a66..b536bc4 100644 (file)
@@ -250,11 +250,11 @@ struct bt_regs {
 
 struct cg6_par {
        spinlock_t              lock;
-       struct bt_regs          *bt;
-       struct cg6_fbc          *fbc;
-       struct cg6_thc          *thc;
-       struct cg6_tec          *tec;
-       volatile u32            *fhc;
+       struct bt_regs          __iomem *bt;
+       struct cg6_fbc          __iomem *fbc;
+       struct cg6_thc          __iomem *thc;
+       struct cg6_tec          __iomem *tec;
+       volatile u32            __iomem *fhc;
 
        u32                     flags;
 #define CG6_FLAG_BLANKED       0x00000001
@@ -269,7 +269,7 @@ struct cg6_par {
 static int cg6_sync(struct fb_info *info)
 {
        struct cg6_par *par = (struct cg6_par *) info->par;
-       struct cg6_fbc *fbc = par->fbc;
+       struct cg6_fbc __iomem *fbc = par->fbc;
        int limit = 10000;
 
        do {
@@ -292,7 +292,7 @@ static int cg6_sync(struct fb_info *info)
 static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
        struct cg6_par *par = (struct cg6_par *) info->par;
-       struct cg6_fbc *fbc = par->fbc;
+       struct cg6_fbc __iomem *fbc = par->fbc;
        unsigned long flags;
        s32 val;
 
@@ -327,7 +327,7 @@ static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
 {
        struct cg6_par *par = (struct cg6_par *) info->par;
-       struct cg6_fbc *fbc = par->fbc;
+       struct cg6_fbc __iomem *fbc = par->fbc;
        const u8 *data = image->data;
        unsigned long flags;
        u32 x, y;
@@ -418,7 +418,7 @@ static int cg6_setcolreg(unsigned regno,
                         unsigned transp, struct fb_info *info)
 {
        struct cg6_par *par = (struct cg6_par *) info->par;
-       struct bt_regs *bt = par->bt;
+       struct bt_regs __iomem *bt = par->bt;
        unsigned long flags;
 
        if (regno >= 256)
@@ -449,24 +449,24 @@ static int
 cg6_blank(int blank, struct fb_info *info)
 {
        struct cg6_par *par = (struct cg6_par *) info->par;
-       struct cg6_thc *thc = par->thc;
+       struct cg6_thc __iomem *thc = par->thc;
        unsigned long flags;
        u32 val;
 
        spin_lock_irqsave(&par->lock, flags);
 
        switch (blank) {
-       case 0: /* Unblanking */
+       case FB_BLANK_UNBLANK: /* Unblanking */
                val = sbus_readl(&thc->thc_misc);
                val |= CG6_THC_MISC_VIDEO;
                sbus_writel(val, &thc->thc_misc);
                par->flags &= ~CG6_FLAG_BLANKED;
                break;
 
-       case 1: /* Normal blanking */
-       case 2: /* VESA blank (vsync off) */
-       case 3: /* VESA blank (hsync off) */
-       case 4: /* Poweroff */
+       case FB_BLANK_NORMAL: /* Normal blanking */
+       case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+       case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+       case FB_BLANK_POWERDOWN: /* Poweroff */
                val = sbus_readl(&thc->thc_misc);
                val &= ~CG6_THC_MISC_VIDEO;
                sbus_writel(val, &thc->thc_misc);
@@ -593,7 +593,7 @@ cg6_init_fix(struct fb_info *info, int linebytes)
 /* Initialize Brooktree DAC */
 static void cg6_bt_init(struct cg6_par *par)
 {
-       struct bt_regs *bt = par->bt;
+       struct bt_regs __iomem *bt = par->bt;
 
        sbus_writel(0x04 << 24, &bt->addr);         /* color planes */
        sbus_writel(0xff << 24, &bt->control);
@@ -608,8 +608,8 @@ static void cg6_bt_init(struct cg6_par *par)
 static void cg6_chip_init(struct fb_info *info)
 {
        struct cg6_par *par = (struct cg6_par *) info->par;
-       struct cg6_tec *tec = par->tec;
-       struct cg6_fbc *fbc = par->fbc;
+       struct cg6_tec __iomem *tec = par->tec;
+       struct cg6_fbc __iomem *fbc = par->fbc;
        u32 rev, conf, mode, tmp;
        int i;
        
@@ -696,34 +696,28 @@ static void cg6_init_one(struct sbus_dev *sdev)
        if (prom_getbool(sdev->prom_node, "dblbuf"))
                all->par.fbsize *= 4;
 
-       all->par.fbc = (struct cg6_fbc *)
-               sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET,
+       all->par.fbc = sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET,
                             4096, "cgsix fbc");
-       all->par.tec = (struct cg6_tec *)
-               sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET,
+       all->par.tec = sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET,
                             sizeof(struct cg6_tec), "cgsix tec");
-       all->par.thc = (struct cg6_thc *)
-               sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET,
+       all->par.thc = sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET,
                             sizeof(struct cg6_thc), "cgsix thc");
-       all->par.bt = (struct bt_regs *)
-               sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET,
+       all->par.bt = sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET,
                             sizeof(struct bt_regs), "cgsix dac");
-       all->par.fhc = (u32 *)
-               sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET,
+       all->par.fhc = sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET,
                             sizeof(u32), "cgsix fhc");
 
        all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
                           FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
        all->info.fbops = &cg6_ops;
 #ifdef CONFIG_SPARC32
-       all->info.screen_base = (char *)
+       all->info.screen_base = (char __iomem *)
                prom_getintdefault(sdev->prom_node, "address", 0);
 #endif
        if (!all->info.screen_base)
-               all->info.screen_base = (char *)
+               all->info.screen_base = 
                        sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET,
                                     all->par.fbsize, "cgsix ram");
-       all->info.currcon = -1;
        all->info.par = &all->par;
 
        all->info.var.accel_flags = FB_ACCELF_TEXT;
index 4ee5a25..a51f4d2 100644 (file)
@@ -416,7 +416,7 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
                release_mem_region(addr, size);
                return -ENOMEM;
        }
-
+       p->device = &dp->dev;
        init_chips(p, addr);
 
 #ifdef CONFIG_PMAC_PBOOK
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");
+
index 32ff420..c52f129 100644 (file)
@@ -10,7 +10,7 @@
 
 static unsigned char fontdata_6x11[FONTDATAMAX] = {
 
-       /* 0 0x00 '^A' */
+       /* 0 0x00 '^@' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -23,405 +23,405 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 1 0x01 '^B' */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       /* 1 0x01 '^A' */
        0x00, /* 00000000 */
+       0x78, /* 0    000 */
+       0x84, /*  0000 00 */
+       0xcc, /*   00  00 */
+       0x84, /*  0000 00 */
+       0xb4, /*  0  0 00 */
+       0x84, /*  0000 00 */
+       0x78, /* 0    000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+
+       /* 2 0x02 '^B' */
        0x00, /* 00000000 */
+       0x78, /* 0    000 */
+       0xfc, /*       00 */
+       0xb4, /*  0  0 00 */
+       0xfc, /*       00 */
+       0xcc, /*   00  00 */
+       0xfc, /*       00 */
+       0x78, /* 0    000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 2 0x02 '^C' */
+       /* 3 0x03 '^C' */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x28, /* 00 0 000 */
+       0x7c, /* 0     00 */
+       0x7c, /* 0     00 */
+       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+
+       /* 4 0x04 '^D' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
+       0x7c, /* 0     00 */
+       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 3 0x03 '^D' */
-       0x00, /* 00000000 */
+       /* 5 0x05 '^E' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x38, /* 00   000 */
+       0x38, /* 00   000 */
+       0x6c, /* 0  0  00 */
+       0x6c, /* 0  0  00 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+
+       /* 6 0x06 '^F' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
+       0x7c, /* 0     00 */
+       0x7c, /* 0     00 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 4 0x04 '^E' */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       /* 7 0x07 '^G' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x30, /* 00  0000 */
+       0x78, /* 0    000 */
+       0x30, /* 00  0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 5 0x05 '^F' */
-       0x00, /* 00000000 */
+       /* 8 0x08 '^H' */
+       0xff, /*          */
+       0xff, /*          */
+       0xff, /*          */
+       0xcf, /*   00     */
+       0x87, /*  0000    */
+       0xcf, /*   00     */
+       0xff, /*          */
+       0xff, /*          */
+       0xff, /*          */
+       0xff, /*          */
+       0xff, /*          */
+
+       /* 9 0x09 '^I' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x30, /* 00  0000 */
+       0x48, /* 0 00 000 */
+       0x84, /*  0000 00 */
+       0x48, /* 0 00 000 */
+       0x30, /* 00  0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+
+       /* 10 0x0a '^J' */
+       0xff, /*          */
+       0xff, /*          */
+       0xcf, /*   00     */
+       0xb7, /*  0  0    */
+       0x7b, /* 0    0   */
+       0xb7, /*  0  0    */
+       0xcf, /*   00     */
+       0xff, /*          */
+       0xff, /*          */
+       0xff, /*          */
+       0xff, /*          */
+
+       /* 11 0x0b '^K' */
        0x00, /* 00000000 */
+       0x3c, /* 00    00 */
+       0x14, /* 000 0 00 */
+       0x20, /* 00 00000 */
+       0x78, /* 0    000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 6 0x06 '^G' */
+       /* 12 0x0c '^L' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
+       0x7c, /* 0     00 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 7 0x07 '^H' */
+       /* 13 0x0d '^M' */
        0x00, /* 00000000 */
        0x3c, /* 00    00 */
+       0x24, /* 00 00 00 */
        0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x20, /* 00 00000 */
+       0x20, /* 00 00000 */
+       0xe0, /*    00000 */
+       0xc0, /*   000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 8 0x08 '^I' */
+       /* 14 0x0e '^N' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x7c, /* 0     00 */
+       0x44, /* 0 000 00 */
+       0x7c, /* 0     00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0xcc, /*   00  00 */
+       0xcc, /*   00  00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 9 0x09 '^J' */
+       /* 15 0x0f '^O' */
+       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x54, /* 0 0 0 00 */
+       0x38, /* 00   000 */
+       0x6c, /* 0  0  00 */
+       0x38, /* 00   000 */
+       0x54, /* 0 0 0 00 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+
+       /* 16 0x10 '^P' */
        0x00, /* 00000000 */
+       0x40, /* 0 000000 */
+       0x60, /* 0  00000 */
+       0x70, /* 0   0000 */
+       0x7c, /* 0     00 */
+       0x70, /* 0   0000 */
+       0x60, /* 0  00000 */
+       0x40, /* 0 000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+
+       /* 17 0x11 '^Q' */
        0x00, /* 00000000 */
+       0x04, /* 00000 00 */
+       0x0c, /* 0000  00 */
+       0x1c, /* 000   00 */
+       0x7c, /* 0     00 */
+       0x1c, /* 000   00 */
+       0x0c, /* 0000  00 */
+       0x04, /* 00000 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 10 0x0a '^K' */
+       /* 18 0x12 '^R' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
+       0x54, /* 0 0 0 00 */
+       0x10, /* 000 0000 */
+       0x54, /* 0 0 0 00 */
+       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 11 0x0b '^L' */
+       /* 19 0x13 '^S' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
        0x00, /* 00000000 */
+       0x48, /* 0 00 000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 12 0x0c '^M' */
        0x00, /* 00000000 */
+
+       /* 20 0x14 '^T' */
        0x3c, /* 00    00 */
+       0x54, /* 0 0 0 00 */
+       0x54, /* 0 0 0 00 */
+       0x54, /* 0 0 0 00 */
        0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x14, /* 000 0 00 */
+       0x14, /* 000 0 00 */
+       0x14, /* 000 0 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 13 0x0d '^N' */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       /* 21 0x15 '^U' */
+       0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x24, /* 00 00 00 */
+       0x50, /* 0 0 0000 */
+       0x48, /* 0 00 000 */
+       0x24, /* 00 00 00 */
+       0x14, /* 000 0 00 */
+       0x48, /* 0 00 000 */
+       0x44, /* 0 000 00 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
+
+       /* 22 0x16 '^V' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 14 0x0e '^O' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0xf8, /*      000 */
+       0xf8, /*      000 */
+       0xf8, /*      000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 15 0x0f '^P' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       /* 23 0x17 '^W' */
        0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
+       0x54, /* 0 0 0 00 */
+       0x10, /* 000 0000 */
+       0x54, /* 0 0 0 00 */
+       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
+       0x7c, /* 0     00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 16 0x10 '^Q' */
+       /* 24 0x18 '^X' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
+       0x54, /* 0 0 0 00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 17 0x11 '^R' */
-       0x00, /* 00000000 */
+       /* 25 0x19 '^Y' */
        0x00, /* 00000000 */
-       0x28, /* 00 0 000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
        0x54, /* 0 0 0 00 */
        0x38, /* 00   000 */
-       0x54, /* 0 0 0 00 */
-       0x28, /* 00 0 000 */
-       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 18 0x12 '^S' */
-       0x04, /* 00000 00 */
-       0x04, /* 00000 00 */
+       /* 26 0x1a '^Z' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
        0x08, /* 0000 000 */
+       0x7c, /* 0     00 */
        0x08, /* 0000 000 */
-       0x50, /* 0 0 0000 */
-       0x50, /* 0 0 0000 */
-       0x20, /* 00 00000 */
-       0x20, /* 00 00000 */
+       0x10, /* 000 0000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 19 0x13 '^T' */
+       /* 27 0x1b '^[' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x10, /* 000 0000 */
-       0x38, /* 00   000 */
+       0x20, /* 00 00000 */
        0x7c, /* 0     00 */
-       0x38, /* 00   000 */
+       0x20, /* 00 00000 */
        0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 20 0x14 '^U' */
-       0x18, /* 000  000 */
-       0x10, /* 000 0000 */
-       0x28, /* 00 0 000 */
-       0x7c, /* 0     00 */
-       0x78, /* 0    000 */
+       /* 28 0x1c '^\' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
        0x78, /* 0    000 */
-       0x7c, /* 0     00 */
-       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 21 0x15 '^V' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 22 0x16 '^W' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 23 0x17 '^X' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 24 0x18 '^Y' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 25 0x19 '^Z' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 26 0x1a '^[' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
+       /* 29 0x1d '^]' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 27 0x1b '^\' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 28 0x1c '^]' */
+       0x48, /* 0 00 000 */
+       0x84, /*  0000 00 */
+       0xfc, /*       00 */
+       0x84, /*  0000 00 */
+       0x48, /* 0 00 000 */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 29 0x1d '^^' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
+       /* 30 0x1e '^^' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 30 0x1e '^_' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
+       0x38, /* 00   000 */
+       0x7c, /* 0     00 */
+       0x7c, /* 0     00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 31 0x1f '^`' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x7c, /* 0     00 */
+       0x7c, /* 0     00 */
+       0x38, /* 00   000 */
+       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -467,16 +467,16 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
 
        /* 35 0x23 '#' */
        0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x28, /* 00 0 000 */
        0x7c, /* 0     00 */
        0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
        0x7c, /* 0     00 */
        0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
 
        /* 36 0x24 '$' */
        0x10, /* 000 0000 */
@@ -493,13 +493,13 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
 
        /* 37 0x25 '%' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x54, /* 0 0 0 00 */
-       0x58, /* 0 0  000 */
-       0x28, /* 00 0 000 */
-       0x34, /* 00  0 00 */
-       0x54, /* 0 0 0 00 */
-       0x48, /* 0 00 000 */
+       0x64, /* 0  00 00 */
+       0x64, /* 0  00 00 */
+       0x08, /* 0000 000 */
+       0x10, /* 000 0000 */
+       0x20, /* 00 00000 */
+       0x4c, /* 0 00  00 */
+       0x4c, /* 0 00  00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -1610,6 +1610,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
 
        /* 123 0x7b '{' */
+       0x04, /* 00000 00 */
        0x08, /* 0000 000 */
        0x08, /* 0000 000 */
        0x08, /* 0000 000 */
@@ -1620,7 +1621,6 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x08, /* 0000 000 */
        0x08, /* 0000 000 */
        0x04, /* 00000 00 */
-       0x00, /* 00000000 */
 
        /* 124 0x7c '|' */
        0x10, /* 000 0000 */
@@ -1636,6 +1636,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
 
        /* 125 0x7d '}' */
+       0x20, /* 00 00000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
@@ -1646,7 +1647,6 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x20, /* 00 00000 */
-       0x00, /* 00000000 */
 
        /* 126 0x7e '~' */
        0x00, /* 00000000 */
@@ -1665,42 +1665,16 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 128 0x80 '\200' */
-       0x00, /* 00000000 */
-       0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x7c, /* 0     00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 129 0x81 '\201' */
+       0x10, /* 000 0000 */
        0x28, /* 00 0 000 */
-       0x38, /* 00   000 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
        0x7c, /* 0     00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 130 0x82 '\202' */
+       /* 128 0x80 '\200' */
        0x00, /* 00000000 */
        0x38, /* 00   000 */
        0x44, /* 0 000 00 */
@@ -1709,65 +1683,39 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x40, /* 0 000000 */
        0x44, /* 0 000 00 */
        0x38, /* 00   000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 131 0x83 '\203' */
        0x10, /* 000 0000 */
-       0x7c, /* 0     00 */
-       0x40, /* 0 000000 */
-       0x40, /* 0 000000 */
-       0x78, /* 0    000 */
-       0x40, /* 0 000000 */
-       0x40, /* 0 000000 */
-       0x7c, /* 0     00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0x20, /* 00 00000 */
        0x00, /* 00000000 */
 
-       /* 132 0x84 '\204' */
-       0x58, /* 0 0  000 */
-       0x44, /* 0 000 00 */
-       0x64, /* 0  00 00 */
-       0x54, /* 0 0 0 00 */
-       0x4c, /* 0 00  00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       /* 129 0x81 '\201' */
        0x00, /* 00000000 */
-
-       /* 133 0x85 '\205' */
+       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
-       0x38, /* 00   000 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x38, /* 00   000 */
+       0x4c, /* 0 00  00 */
+       0x34, /* 00  0 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 134 0x86 '\206' */
+       /* 130 0x82 '\202' */
+       0x08, /* 0000 000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
        0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x7c, /* 0     00 */
+       0x40, /* 0 000000 */
+       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 135 0x87 '\207' */
-       0x08, /* 0000 000 */
+       /* 131 0x83 '\203' */
        0x10, /* 000 0000 */
+       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x3c, /* 00    00 */
        0x44, /* 0 000 00 */
@@ -1778,9 +1726,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 136 0x88 '\210' */
-       0x10, /* 000 0000 */
-       0x08, /* 0000 000 */
+       /* 132 0x84 '\204' */
+       0x00, /* 00000000 */
+       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x3c, /* 00    00 */
        0x44, /* 0 000 00 */
@@ -1791,9 +1739,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 137 0x89 '\211' */
+       /* 133 0x85 '\205' */
        0x10, /* 000 0000 */
-       0x28, /* 00 0 000 */
+       0x08, /* 0000 000 */
        0x00, /* 00000000 */
        0x3c, /* 00    00 */
        0x44, /* 0 000 00 */
@@ -1804,10 +1752,10 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 138 0x8a '\212' */
-       0x00, /* 00000000 */
-       0x28, /* 00 0 000 */
-       0x00, /* 00000000 */
+       /* 134 0x86 '\206' */
+       0x18, /* 000  000 */
+       0x24, /* 00 00 00 */
+       0x18, /* 000  000 */
        0x3c, /* 00    00 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
@@ -1817,33 +1765,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 139 0x8b '\213' */
-       0x34, /* 00  0 00 */
-       0x58, /* 0 0  000 */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x4c, /* 0 00  00 */
-       0x34, /* 00  0 00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 140 0x8c '\214' */
-       0x18, /* 000  000 */
-       0x24, /* 00 00 00 */
-       0x18, /* 000  000 */
-       0x3c, /* 00    00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x4c, /* 0 00  00 */
-       0x34, /* 00  0 00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 141 0x8d '\215' */
+       /* 135 0x87 '\207' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -1856,9 +1778,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x20, /* 00 00000 */
        0x00, /* 00000000 */
 
-       /* 142 0x8e '\216' */
-       0x08, /* 0000 000 */
+       /* 136 0x88 '\210' */
        0x10, /* 000 0000 */
+       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x38, /* 00   000 */
        0x44, /* 0 000 00 */
@@ -1869,9 +1791,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 143 0x8f '\217' */
-       0x20, /* 00 00000 */
-       0x10, /* 000 0000 */
+       /* 137 0x89 '\211' */
+       0x00, /* 00000000 */
+       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x38, /* 00   000 */
        0x44, /* 0 000 00 */
@@ -1882,9 +1804,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 144 0x90 '\220' */
+       /* 138 0x8a '\212' */
+       0x20, /* 00 00000 */
        0x10, /* 000 0000 */
-       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x38, /* 00   000 */
        0x44, /* 0 000 00 */
@@ -1895,23 +1817,10 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 145 0x91 '\221' */
+       /* 139 0x8b '\213' */
        0x00, /* 00000000 */
        0x28, /* 00 0 000 */
        0x00, /* 00000000 */
-       0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x7c, /* 0     00 */
-       0x40, /* 0 000000 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 146 0x92 '\222' */
-       0x08, /* 0000 000 */
-       0x10, /* 000 0000 */
-       0x00, /* 00000000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
@@ -1921,9 +1830,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 147 0x93 '\223' */
-       0x20, /* 00 00000 */
+       /* 140 0x8c '\214' */
        0x10, /* 000 0000 */
+       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
@@ -1934,9 +1843,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 148 0x94 '\224' */
+       /* 141 0x8d '\215' */
+       0x20, /* 00 00000 */
        0x10, /* 000 0000 */
-       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
@@ -1947,25 +1856,25 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 149 0x95 '\225' */
-       0x00, /* 00000000 */
-       0x28, /* 00 0 000 */
-       0x00, /* 00000000 */
-       0x10, /* 000 0000 */
-       0x10, /* 000 0000 */
-       0x10, /* 000 0000 */
-       0x10, /* 000 0000 */
-       0x10, /* 000 0000 */
+       /* 142 0x8e '\216' */
+       0x84, /*  0000 00 */
+       0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x7c, /* 0     00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 150 0x96 '\226' */
-       0x34, /* 00  0 00 */
-       0x58, /* 0 0  000 */
-       0x00, /* 00000000 */
+       /* 143 0x8f '\217' */
        0x58, /* 0 0  000 */
-       0x64, /* 0  00 00 */
+       0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x7c, /* 0     00 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
@@ -1973,33 +1882,46 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 151 0x97 '\227' */
-       0x08, /* 0000 000 */
+       /* 144 0x90 '\220' */
        0x10, /* 000 0000 */
+       0x7c, /* 0     00 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
+       0x78, /* 0    000 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
+       0x7c, /* 0     00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 145 0x91 '\221' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x38, /* 00   000 */
+       0x54, /* 0 0 0 00 */
+       0x5c, /* 0 0   00 */
+       0x50, /* 0 0 0000 */
+       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 152 0x98 '\230' */
-       0x20, /* 00 00000 */
-       0x10, /* 000 0000 */
+       /* 146 0x92 '\222' */
        0x00, /* 00000000 */
-       0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x38, /* 00   000 */
+       0x3c, /* 00    00 */
+       0x50, /* 0 0 0000 */
+       0x50, /* 0 0 0000 */
+       0x78, /* 0    000 */
+       0x50, /* 0 0 0000 */
+       0x50, /* 0 0 0000 */
+       0x5c, /* 0 0   00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 153 0x99 '\231' */
+       /* 147 0x93 '\223' */
        0x10, /* 000 0000 */
        0x28, /* 00 0 000 */
        0x00, /* 00000000 */
@@ -2012,7 +1934,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 154 0x9a '\232' */
+       /* 148 0x94 '\224' */
        0x00, /* 00000000 */
        0x28, /* 00 0 000 */
        0x00, /* 00000000 */
@@ -2025,9 +1947,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 155 0x9b '\233' */
-       0x34, /* 00  0 00 */
-       0x58, /* 0 0  000 */
+       /* 149 0x95 '\225' */
+       0x20, /* 00 00000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x38, /* 00   000 */
        0x44, /* 0 000 00 */
@@ -2038,9 +1960,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 156 0x9c '\234' */
-       0x08, /* 0000 000 */
+       /* 150 0x96 '\226' */
        0x10, /* 000 0000 */
+       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
@@ -2051,7 +1973,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 157 0x9d '\235' */
+       /* 151 0x97 '\227' */
        0x20, /* 00 00000 */
        0x10, /* 000 0000 */
        0x00, /* 00000000 */
@@ -2064,59 +1986,46 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 158 0x9e '\236' */
-       0x10, /* 000 0000 */
+       /* 152 0x98 '\230' */
+       0x00, /* 00000000 */
        0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
-       0x4c, /* 0 00  00 */
-       0x34, /* 00  0 00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0x44, /* 0 000 00 */
+       0x3c, /* 00    00 */
+       0x04, /* 00000 00 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
 
-       /* 159 0x9f '\237' */
-       0x00, /* 00000000 */
-       0x28, /* 00 0 000 */
-       0x00, /* 00000000 */
+       /* 153 0x99 '\231' */
+       0x84, /*  0000 00 */
+       0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
        0x44, /* 0 000 00 */
-       0x4c, /* 0 00  00 */
-       0x34, /* 00  0 00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 160 0xa0 '\240' */
-       0x00, /* 00000000 */
-       0x10, /* 000 0000 */
        0x38, /* 00   000 */
-       0x10, /* 000 0000 */
-       0x10, /* 000 0000 */
-       0x10, /* 000 0000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 161 0xa1 '\241' */
-       0x18, /* 000  000 */
-       0x24, /* 00 00 00 */
-       0x24, /* 00 00 00 */
-       0x18, /* 000  000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       /* 154 0x9a '\232' */
+       0x88, /*  000 000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 162 0xa2 '\242' */
+       /* 155 0x9b '\233' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x10, /* 000 0000 */
@@ -2129,7 +2038,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 163 0xa3 '\243' */
+       /* 156 0x9c '\234' */
        0x30, /* 00  0000 */
        0x48, /* 0 00 000 */
        0x40, /* 0 000000 */
@@ -2142,293 +2051,295 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 164 0xa4 '\244' */
+       /* 157 0x9d '\235' */
+       0x00, /* 00000000 */
        0x44, /* 0 000 00 */
-       0x24, /* 00 00 00 */
-       0x50, /* 0 0 0000 */
+       0x28, /* 00 0 000 */
+       0x7c, /* 0     00 */
+       0x10, /* 000 0000 */
+       0x7c, /* 0     00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 158 0x9e '\236' */
+       0x00, /* 00000000 */
+       0x70, /* 0   0000 */
        0x48, /* 0 00 000 */
-       0x24, /* 00 00 00 */
-       0x14, /* 000 0 00 */
+       0x70, /* 0   0000 */
+       0x48, /* 0 00 000 */
+       0x5c, /* 0 0   00 */
        0x48, /* 0 00 000 */
        0x44, /* 0 000 00 */
-       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 165 0xa5 '\245' */
        0x00, /* 00000000 */
+
+       /* 159 0x9f '\237' */
        0x00, /* 00000000 */
+       0x0c, /* 0000  00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
        0x38, /* 00   000 */
-       0x7c, /* 0     00 */
-       0x7c, /* 0     00 */
-       0x7c, /* 0     00 */
-       0x38, /* 00   000 */
-       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x60, /* 0  00000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 166 0xa6 '\246' */
-       0x3c, /* 00    00 */
-       0x54, /* 0 0 0 00 */
-       0x54, /* 0 0 0 00 */
-       0x54, /* 0 0 0 00 */
+       /* 160 0xa0 '\240' */
+       0x08, /* 0000 000 */
+       0x10, /* 000 0000 */
+       0x00, /* 00000000 */
        0x3c, /* 00    00 */
-       0x14, /* 000 0 00 */
-       0x14, /* 000 0 00 */
-       0x14, /* 000 0 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x4c, /* 0 00  00 */
+       0x34, /* 00  0 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 167 0xa7 '\247' */
-       0x18, /* 000  000 */
-       0x24, /* 00 00 00 */
-       0x44, /* 0 000 00 */
-       0x48, /* 0 00 000 */
-       0x48, /* 0 00 000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x58, /* 0 0  000 */
-       0x40, /* 0 000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 168 0xa8 '\250' */
-       0x00, /* 00000000 */
-       0x70, /* 0   0000 */
+       /* 161 0xa1 '\241' */
        0x08, /* 0000 000 */
-       0x64, /* 0  00 00 */
-       0x54, /* 0 0 0 00 */
-       0x64, /* 0  00 00 */
-       0x58, /* 0 0  000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 169 0xa9 '\251' */
-       0x00, /* 00000000 */
-       0x70, /* 0   0000 */
+       /* 162 0xa2 '\242' */
        0x08, /* 0000 000 */
-       0x34, /* 00  0 00 */
+       0x10, /* 000 0000 */
+       0x00, /* 00000000 */
+       0x38, /* 00   000 */
        0x44, /* 0 000 00 */
-       0x34, /* 00  0 00 */
-       0x08, /* 0000 000 */
-       0x70, /* 0   0000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 170 0xaa '\252' */
+       /* 163 0xa3 '\243' */
+       0x08, /* 0000 000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
-       0xf4, /*     0 00 */
-       0x5c, /* 0 0   00 */
-       0x5c, /* 0 0   00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x4c, /* 0 00  00 */
+       0x34, /* 00  0 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+
+       /* 164 0xa4 '\244' */
+       0x34, /* 00  0 00 */
+       0x58, /* 0 0  000 */
        0x00, /* 00000000 */
+       0x58, /* 0 0  000 */
+       0x64, /* 0  00 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 171 0xab '\253' */
+       /* 165 0xa5 '\245' */
+       0x58, /* 0 0  000 */
+       0x44, /* 0 000 00 */
+       0x64, /* 0  00 00 */
+       0x54, /* 0 0 0 00 */
+       0x4c, /* 0 00  00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
        0x00, /* 00000000 */
-       0x08, /* 0000 000 */
-       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+
+       /* 166 0xa6 '\246' */
        0x00, /* 00000000 */
+       0x1c, /* 000   00 */
+       0x24, /* 00 00 00 */
+       0x24, /* 00 00 00 */
+       0x1c, /* 000   00 */
        0x00, /* 00000000 */
+       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 172 0xac '\254' */
-       0x00, /* 00000000 */
-       0x28, /* 00 0 000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       /* 167 0xa7 '\247' */
        0x00, /* 00000000 */
+       0x18, /* 000  000 */
+       0x24, /* 00 00 00 */
+       0x24, /* 00 00 00 */
+       0x18, /* 000  000 */
        0x00, /* 00000000 */
+       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 173 0xad '\255' */
+       /* 168 0xa8 '\250' */
        0x00, /* 00000000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
-       0x08, /* 0000 000 */
-       0x7c, /* 0     00 */
        0x10, /* 000 0000 */
-       0x7c, /* 0     00 */
        0x20, /* 00 00000 */
-       0x00, /* 00000000 */
+       0x40, /* 0 000000 */
+       0x44, /* 0 000 00 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 174 0xae '\256' */
+       /* 169 0xa9 '\251' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x50, /* 0 0 0000 */
-       0x50, /* 0 0 0000 */
-       0x78, /* 0    000 */
-       0x50, /* 0 0 0000 */
-       0x50, /* 0 0 0000 */
-       0x5c, /* 0 0   00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 175 0xaf '\257' */
+       0x7c, /* 0     00 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
        0x00, /* 00000000 */
-       0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x4c, /* 0 00  00 */
-       0x54, /* 0 0 0 00 */
-       0x64, /* 0  00 00 */
-       0x44, /* 0 000 00 */
-       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 176 0xb0 '\260' */
+       /* 170 0xaa '\252' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x6c, /* 0  0  00 */
-       0x54, /* 0 0 0 00 */
-       0x6c, /* 0  0  00 */
        0x00, /* 00000000 */
+       0x7c, /* 0     00 */
+       0x04, /* 00000 00 */
+       0x04, /* 00000 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 177 0xb1 '\261' */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x10, /* 000 0000 */
-       0x10, /* 000 0000 */
-       0x7c, /* 0     00 */
-       0x10, /* 000 0000 */
+       /* 171 0xab '\253' */
+       0x20, /* 00 00000 */
+       0x60, /* 0  00000 */
+       0x24, /* 00 00 00 */
+       0x28, /* 00 0 000 */
        0x10, /* 000 0000 */
-       0x7c, /* 0     00 */
-       0x00, /* 00000000 */
+       0x28, /* 00 0 000 */
+       0x44, /* 0 000 00 */
+       0x08, /* 0000 000 */
+       0x1c, /* 000   00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 178 0xb2 '\262' */
-       0x00, /* 00000000 */
-       0x08, /* 0000 000 */
-       0x10, /* 000 0000 */
+       /* 172 0xac '\254' */
        0x20, /* 00 00000 */
+       0x60, /* 0  00000 */
+       0x24, /* 00 00 00 */
+       0x28, /* 00 0 000 */
        0x10, /* 000 0000 */
+       0x28, /* 00 0 000 */
+       0x58, /* 0 0  000 */
+       0x3c, /* 00    00 */
        0x08, /* 0000 000 */
        0x00, /* 00000000 */
-       0x38, /* 00   000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 179 0xb3 '\263' */
+       /* 173 0xad '\255' */
        0x00, /* 00000000 */
-       0x10, /* 000 0000 */
-       0x08, /* 0000 000 */
-       0x04, /* 00000 00 */
        0x08, /* 0000 000 */
-       0x10, /* 000 0000 */
        0x00, /* 00000000 */
-       0x1c, /* 000   00 */
+       0x08, /* 0000 000 */
+       0x08, /* 0000 000 */
+       0x08, /* 0000 000 */
+       0x08, /* 0000 000 */
+       0x08, /* 0000 000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 180 0xb4 '\264' */
-       0x00, /* 00000000 */
-       0x44, /* 0 000 00 */
-       0x28, /* 00 0 000 */
-       0x7c, /* 0     00 */
-       0x10, /* 000 0000 */
-       0x7c, /* 0     00 */
-       0x10, /* 000 0000 */
-       0x10, /* 000 0000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       /* 174 0xae '\256' */
        0x00, /* 00000000 */
-
-       /* 181 0xb5 '\265' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x24, /* 00 00 00 */
        0x48, /* 0 00 000 */
        0x48, /* 0 00 000 */
-       0x48, /* 0 00 000 */
-       0x48, /* 0 00 000 */
-       0x74, /* 0   0 00 */
-       0x40, /* 0 000000 */
-       0x40, /* 0 000000 */
-       0x00, /* 00000000 */
-
-       /* 182 0xb6 '\266' */
-       0x00, /* 00000000 */
-       0x10, /* 000 0000 */
-       0x08, /* 0000 000 */
-       0x0c, /* 0000  00 */
-       0x14, /* 000 0 00 */
-       0x24, /* 00 00 00 */
        0x24, /* 00 00 00 */
-       0x18, /* 000  000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 183 0xb7 '\267' */
-       0x00, /* 00000000 */
-       0x7c, /* 0     00 */
-       0x24, /* 00 00 00 */
-       0x10, /* 000 0000 */
-       0x08, /* 0000 000 */
-       0x10, /* 000 0000 */
-       0x24, /* 00 00 00 */
-       0x7c, /* 0     00 */
+       /* 175 0xaf '\257' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 184 0xb8 '\270' */
        0x00, /* 00000000 */
-       0x7c, /* 0     00 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
+       0x48, /* 0 00 000 */
+       0x24, /* 00 00 00 */
+       0x24, /* 00 00 00 */
+       0x48, /* 0 00 000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 185 0xb9 '\271' */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x7c, /* 0     00 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       /* 176 0xb0 '\260' */
+       0x11, /* 000 000  */
+       0x44, /* 0 000 00 */
+       0x11, /* 000 000  */
+       0x44, /* 0 000 00 */
+       0x11, /* 000 000  */
+       0x44, /* 0 000 00 */
+       0x11, /* 000 000  */
+       0x44, /* 0 000 00 */
+       0x11, /* 000 000  */
+       0x44, /* 0 000 00 */
+       0x11, /* 000 000  */
 
-       /* 186 0xba '\272' */
+       /* 177 0xb1 '\261' */
+       0x55, /* 0 0 0 0  */
+       0xaa, /*  0 0 0 0 */
+       0x55, /* 0 0 0 0  */
+       0xaa, /*  0 0 0 0 */
+       0x55, /* 0 0 0 0  */
+       0xaa, /*  0 0 0 0 */
+       0x55, /* 0 0 0 0  */
+       0xaa, /*  0 0 0 0 */
+       0x55, /* 0 0 0 0  */
+       0xaa, /*  0 0 0 0 */
+       0x55, /* 0 0 0 0  */
+
+       /* 178 0xb2 '\262' */
+       0xdd, /*   0   0  */
+       0x77, /* 0   0    */
+       0xdd, /*   0   0  */
+       0x77, /* 0   0    */
+       0xdd, /*   0   0  */
+       0x77, /* 0   0    */
+       0xdd, /*   0   0  */
+       0x77, /* 0   0    */
+       0xdd, /*   0   0  */
+       0x77, /* 0   0    */
+       0xdd, /*   0   0  */
+
+       /* 179 0xb3 '\263' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
@@ -2438,58 +2349,147 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
-       0x60, /* 0  00000 */
-       0x00, /* 00000000 */
 
-       /* 187 0xbb '\273' */
-       0x00, /* 00000000 */
-       0x1c, /* 000   00 */
-       0x24, /* 00 00 00 */
-       0x24, /* 00 00 00 */
-       0x1c, /* 000   00 */
+       /* 180 0xb4 '\264' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0xf0, /*     0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+
+       /* 181 0xb5 '\265' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0xf0, /*     0000 */
+       0x10, /* 000 0000 */
+       0xf0, /*     0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+
+       /* 182 0xb6 '\266' */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0xe8, /*    0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+
+       /* 183 0xb7 '\267' */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0xf8, /*      000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+
+       /* 184 0xb8 '\270' */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0xf0, /*     0000 */
+       0x10, /* 000 0000 */
+       0xf0, /*     0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
 
-       /* 188 0xbc '\274' */
+       /* 185 0xb9 '\271' */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0xe8, /*    0 000 */
+       0x08, /* 0000 000 */
+       0xe8, /*    0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+
+       /* 186 0xba '\272' */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+
+       /* 187 0xbb '\273' */
        0x00, /* 00000000 */
-       0x18, /* 000  000 */
-       0x24, /* 00 00 00 */
-       0x24, /* 00 00 00 */
-       0x18, /* 000  000 */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0xf8, /*      000 */
+       0x08, /* 0000 000 */
+       0xe8, /*    0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+
+       /* 188 0xbc '\274' */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0xe8, /*    0 000 */
+       0x08, /* 0000 000 */
+       0xf8, /*      000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 189 0xbd '\275' */
-       0x00, /* 00000000 */
-       0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
        0x28, /* 00 0 000 */
-       0x6c, /* 0  0  00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0xf8, /*      000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 190 0xbe '\276' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0xf0, /*     0000 */
+       0x10, /* 000 0000 */
+       0xf0, /*     0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x38, /* 00   000 */
-       0x54, /* 0 0 0 00 */
-       0x5c, /* 0 0   00 */
-       0x50, /* 0 0 0000 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
@@ -2497,152 +2497,152 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x38, /* 00   000 */
-       0x4c, /* 0 00  00 */
-       0x54, /* 0 0 0 00 */
-       0x64, /* 0  00 00 */
-       0x38, /* 00   000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0xf0, /*     0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
 
        /* 192 0xc0 '\300' */
-       0x00, /* 00000000 */
        0x10, /* 000 0000 */
-       0x00, /* 00000000 */
        0x10, /* 000 0000 */
-       0x20, /* 00 00000 */
-       0x40, /* 0 000000 */
-       0x44, /* 0 000 00 */
-       0x38, /* 00   000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x1c, /* 000   00 */
        0x00, /* 00000000 */
-
-       /* 193 0xc1 '\301' */
        0x00, /* 00000000 */
-       0x08, /* 0000 000 */
        0x00, /* 00000000 */
-       0x08, /* 0000 000 */
-       0x08, /* 0000 000 */
-       0x08, /* 0000 000 */
-       0x08, /* 0000 000 */
-       0x08, /* 0000 000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 194 0xc2 '\302' */
+       /* 193 0xc1 '\301' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x7c, /* 0     00 */
-       0x04, /* 00000 00 */
-       0x04, /* 00000 00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
-       /* 195 0xc3 '\303' */
-       0x00, /* 00000000 */
+       /* 194 0xc2 '\302' */
        0x00, /* 00000000 */
-       0x0c, /* 0000  00 */
-       0x08, /* 0000 000 */
-       0x10, /* 000 0000 */
-       0x50, /* 0 0 0000 */
-       0x20, /* 00 00000 */
-       0x20, /* 00 00000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0xfc, /*       00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
 
-       /* 196 0xc4 '\304' */
+       /* 195 0xc3 '\303' */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
-       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
+       0x1c, /* 000   00 */
+       0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
        0x10, /* 000 0000 */
-       0x60, /* 0  00000 */
-       0x00, /* 00000000 */
 
-       /* 197 0xc5 '\305' */
+       /* 196 0xc4 '\304' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x04, /* 00000 00 */
-       0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x38, /* 00   000 */
-       0x40, /* 0 000000 */
-       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
-
-       /* 198 0xc6 '\306' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x10, /* 000 0000 */
-       0x10, /* 000 0000 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
-       0x44, /* 0 000 00 */
-       0x7c, /* 0     00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
+       /* 197 0xc5 '\305' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0xfc, /*       00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+
+       /* 198 0xc6 '\306' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x1c, /* 000   00 */
+       0x10, /* 000 0000 */
+       0x1c, /* 000   00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+
        /* 199 0xc7 '\307' */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x24, /* 00 00 00 */
-       0x48, /* 0 00 000 */
-       0x48, /* 0 00 000 */
-       0x24, /* 00 00 00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x2c, /* 00 0  00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
 
        /* 200 0xc8 '\310' */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x2c, /* 00 0  00 */
+       0x20, /* 00 00000 */
+       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x48, /* 0 00 000 */
-       0x24, /* 00 00 00 */
-       0x24, /* 00 00 00 */
-       0x48, /* 0 00 000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 201 0xc9 '\311' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x54, /* 0 0 0 00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0x3c, /* 00    00 */
+       0x20, /* 00 00000 */
+       0x2c, /* 00 0  00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
 
        /* 202 0xca '\312' */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0xec, /*    0  00 */
        0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -2650,76 +2650,76 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
 
        /* 203 0xcb '\313' */
-       0x10, /* 000 0000 */
-       0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x7c, /* 0     00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0xfc, /*       00 */
+       0x00, /* 00000000 */
+       0xec, /*    0  00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
 
        /* 204 0xcc '\314' */
-       0x58, /* 0 0  000 */
-       0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x7c, /* 0     00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x2c, /* 00 0  00 */
+       0x20, /* 00 00000 */
+       0x2c, /* 00 0  00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+
+       /* 205 0xcd '\315' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 205 0xcd '\315' */
-       0x58, /* 0 0  000 */
-       0x38, /* 00   000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x38, /* 00   000 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 206 0xce '\316' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x50, /* 0 0 0000 */
-       0x50, /* 0 0 0000 */
-       0x58, /* 0 0  000 */
-       0x50, /* 0 0 0000 */
-       0x50, /* 0 0 0000 */
-       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+
+       /* 206 0xce '\316' */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0xec, /*    0  00 */
        0x00, /* 00000000 */
+       0xec, /*    0  00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
 
        /* 207 0xcf '\317' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x28, /* 00 0 000 */
-       0x54, /* 0 0 0 00 */
-       0x5c, /* 0 0   00 */
-       0x50, /* 0 0 0000 */
-       0x2c, /* 00 0  00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 208 0xd0 '\320' */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x38, /* 00   000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -2731,34 +2731,34 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x00, /* 00000000 */
        0xfc, /*       00 */
        0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0xfc, /*       00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
 
        /* 210 0xd2 '\322' */
        0x00, /* 00000000 */
-       0x14, /* 000 0 00 */
-       0x28, /* 00 0 000 */
-       0x28, /* 00 0 000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0xfc, /*       00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
 
        /* 211 0xd3 '\323' */
-       0x00, /* 00000000 */
-       0x14, /* 000 0 00 */
-       0x14, /* 000 0 00 */
        0x28, /* 00 0 000 */
-       0x00, /* 00000000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -2767,12 +2767,12 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
 
        /* 212 0xd4 '\324' */
-       0x00, /* 00000000 */
-       0x08, /* 0000 000 */
        0x10, /* 000 0000 */
-       0x18, /* 000  000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x1c, /* 000   00 */
+       0x10, /* 000 0000 */
+       0x1c, /* 000   00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -2781,64 +2781,64 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
 
        /* 213 0xd5 '\325' */
        0x00, /* 00000000 */
-       0x18, /* 000  000 */
-       0x08, /* 0000 000 */
-       0x10, /* 000 0000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 214 0xd6 '\326' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x1c, /* 000   00 */
+       0x10, /* 000 0000 */
+       0x1c, /* 000   00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
        0x10, /* 000 0000 */
-       0x00, /* 00000000 */
-       0x7c, /* 0     00 */
-       0x00, /* 00000000 */
        0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+
+       /* 214 0xd6 '\326' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x3c, /* 00    00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
 
        /* 215 0xd7 '\327' */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x10, /* 000 0000 */
        0x28, /* 00 0 000 */
-       0x44, /* 0 000 00 */
        0x28, /* 00 0 000 */
-       0x10, /* 000 0000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0xfc, /*       00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
 
        /* 216 0xd8 '\330' */
-       0x00, /* 00000000 */
-       0x28, /* 00 0 000 */
-       0x00, /* 00000000 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x44, /* 0 000 00 */
-       0x3c, /* 00    00 */
-       0x04, /* 00000 00 */
-       0x38, /* 00   000 */
-       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0xfc, /*       00 */
+       0x10, /* 000 0000 */
+       0xfc, /*       00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
 
        /* 217 0xd9 '\331' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0xf0, /*     0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0xfc, /*       00 */
-       0x00, /* 00000000 */
-       0xfc, /*       00 */
-       0x00, /* 00000000 */
-       0xfc, /*       00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -2846,272 +2846,272 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
 
        /* 218 0xda '\332' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x1f, /* 000      */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
 
        /* 219 0xdb '\333' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
 
        /* 220 0xdc '\334' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-
-       /* 221 0xdd '\335' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+
+       /* 221 0xdd '\335' */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
+       0xe0, /*    00000 */
 
        /* 222 0xde '\336' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
+       0x1c, /* 000   00 */
 
        /* 223 0xdf '\337' */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0xfc, /*       00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 224 0xe0 '\340' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x24, /* 00 00 00 */
+       0x58, /* 0 0  000 */
+       0x50, /* 0 0 0000 */
+       0x54, /* 0 0 0 00 */
+       0x2c, /* 00 0  00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 225 0xe1 '\341' */
-       0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
+       0x18, /* 000  000 */
+       0x24, /* 00 00 00 */
+       0x44, /* 0 000 00 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x58, /* 0 0  000 */
+       0x40, /* 0 000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 226 0xe2 '\342' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x7c, /* 0     00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 227 0xe3 '\343' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7c, /* 0     00 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 228 0xe4 '\344' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x7c, /* 0     00 */
+       0x24, /* 00 00 00 */
+       0x10, /* 000 0000 */
+       0x08, /* 0000 000 */
+       0x10, /* 000 0000 */
+       0x24, /* 00 00 00 */
+       0x7c, /* 0     00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 229 0xe5 '\345' */
        0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
+       0x30, /* 00  0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 230 0xe6 '\346' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
+       0x48, /* 0 00 000 */
+       0x74, /* 0   0 00 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
        0x00, /* 00000000 */
 
        /* 231 0xe7 '\347' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x6c, /* 0  0  00 */
+       0x98, /*  00  000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 232 0xe8 '\350' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 233 0xe9 '\351' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x38, /* 00   000 */
+       0x4c, /* 0 00  00 */
+       0x54, /* 0 0 0 00 */
+       0x64, /* 0  00 00 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 234 0xea '\352' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x28, /* 00 0 000 */
+       0x6c, /* 0  0  00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 235 0xeb '\353' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x10, /* 000 0000 */
+       0x08, /* 0000 000 */
+       0x0c, /* 0000  00 */
+       0x14, /* 000 0 00 */
+       0x24, /* 00 00 00 */
+       0x24, /* 00 00 00 */
+       0x18, /* 000  000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 236 0xec '\354' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x38, /* 00   000 */
+       0x54, /* 0 0 0 00 */
+       0x54, /* 0 0 0 00 */
+       0x54, /* 0 0 0 00 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 237 0xed '\355' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x04, /* 00000 00 */
+       0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x38, /* 00   000 */
+       0x40, /* 0 000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-       /* 238 0xee '\356' */
+       0x00, /* 00000000 */
+
+       /* 238 0xee '\356' */
        0x00, /* 00000000 */
        0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
+       0x78, /* 0    000 */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
        0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -3119,221 +3119,221 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
 
        /* 239 0xef '\357' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x38, /* 00   000 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
+       0x44, /* 0 000 00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 240 0xf0 '\360' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0xfc, /*       00 */
+       0x00, /* 00000000 */
+       0xfc, /*       00 */
+       0x00, /* 00000000 */
+       0xfc, /*       00 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 241 0xf1 '\361' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x7c, /* 0     00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x7c, /* 0     00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 242 0xf2 '\362' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x10, /* 000 0000 */
+       0x08, /* 0000 000 */
+       0x04, /* 00000 00 */
+       0x08, /* 0000 000 */
+       0x10, /* 000 0000 */
+       0x00, /* 00000000 */
+       0x1c, /* 000   00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 243 0xf3 '\363' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x08, /* 0000 000 */
+       0x10, /* 000 0000 */
+       0x20, /* 00 00000 */
+       0x10, /* 000 0000 */
+       0x08, /* 0000 000 */
+       0x00, /* 00000000 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 244 0xf4 '\364' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
-       0x00, /* 00000000 */
+       0x0c, /* 0000  00 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
 
        /* 245 0xf5 '\365' */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x10, /* 000 0000 */
+       0x60, /* 0  00000 */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+
+       /* 246 0xf6 '\366' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
-
-       /* 246 0xf6 '\366' */
+       0x7c, /* 0     00 */
+       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 247 0xf7 '\367' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x34, /* 00  0 00 */
+       0x48, /* 0 00 000 */
+       0x00, /* 00000000 */
+       0x34, /* 00  0 00 */
+       0x48, /* 0 00 000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 248 0xf8 '\370' */
+       0x18, /* 000  000 */
+       0x24, /* 00 00 00 */
+       0x24, /* 00 00 00 */
+       0x18, /* 000  000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 249 0xf9 '\371' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x38, /* 00   000 */
+       0x10, /* 000 0000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 250 0xfa '\372' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x10, /* 000 0000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 251 0xfb '\373' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x0c, /* 0000  00 */
+       0x08, /* 0000 000 */
+       0x10, /* 000 0000 */
+       0x50, /* 0 0 0000 */
+       0x20, /* 00 00000 */
+       0x20, /* 00 00000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 252 0xfc '\374' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x50, /* 0 0 0000 */
+       0x28, /* 00 0 000 */
+       0x28, /* 00 0 000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 253 0xfd '\375' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x70, /* 0   0000 */
+       0x08, /* 0000 000 */
+       0x20, /* 00 00000 */
+       0x78, /* 0    000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 254 0xfe '\376' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x38, /* 00   000 */
+       0x38, /* 00   000 */
+       0x38, /* 00   000 */
+       0x38, /* 00   000 */
+       0x38, /* 00   000 */
+       0x38, /* 00   000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
 
        /* 255 0xff '\377' */
        0x00, /* 00000000 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
-       0x3c, /* 00    00 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
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");
+
index 22896d6..f0eb993 100644 (file)
@@ -98,14 +98,14 @@ struct fb_info_control {
        struct fb_par_control   par;
        u32                     pseudo_palette[17];
                
-       struct cmap_regs        *cmap_regs;
+       struct cmap_regs        __iomem *cmap_regs;
        unsigned long           cmap_regs_phys;
        
-       struct control_regs     *control_regs;
+       struct control_regs     __iomem *control_regs;
        unsigned long           control_regs_phys;
        unsigned long           control_regs_size;
        
-       __u8                    *frame_buffer;
+       __u8                    __iomem *frame_buffer;
        unsigned long           frame_buffer_phys;
        unsigned long           fb_orig_base;
        unsigned long           fb_orig_size;
@@ -329,17 +329,17 @@ static int controlfb_blank(int blank_mode, struct fb_info *info)
 
        ctrl = ld_le32(CNTRL_REG(p,ctrl));
        if (blank_mode > 0)
-               switch (blank_mode - 1) {
-               case VESA_VSYNC_SUSPEND:
+               switch (blank_mode) {
+               case FB_BLANK_VSYNC_SUSPEND:
                        ctrl &= ~3;
                        break;
-               case VESA_HSYNC_SUSPEND:
+               case FB_BLANK_HSYNC_SUSPEND:
                        ctrl &= ~0x30;
                        break;
-               case VESA_POWERDOWN:
+               case FB_BLANK_POWERDOWN:
                        ctrl &= ~0x33;
                        /* fall through */
-               case VESA_NO_BLANKING:
+               case FB_BLANK_NORMAL:
                        ctrl |= 0x400;
                        break;
                default:
@@ -497,7 +497,7 @@ try_again:
 static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par)
 {
        struct control_regvals  *r;
-       volatile struct preg    *rp;
+       volatile struct preg    __iomem *rp;
        int                     i, cmode;
 
        if (PAR_EQUAL(&p->par, par)) {
@@ -1017,7 +1017,7 @@ static void __init control_init_info(struct fb_info *info, struct fb_info_contro
        info->fbops = &controlfb_ops;
        info->pseudo_palette = p->pseudo_palette;
         info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
-       info->screen_base = (char *) p->frame_buffer + CTRLFB_OFF;
+       info->screen_base = p->frame_buffer + CTRLFB_OFF;
 
        fb_alloc_cmap(&info->cmap, 256, 0);
 
index 261d157..bd7e1c0 100644 (file)
@@ -466,8 +466,8 @@ struct cfb_info;
 
 struct cyberpro_info {
        struct pci_dev  *dev;
-       unsigned char   *regs;
-       char            *fb;
+       unsigned char   __iomem *regs;
+       char            __iomem *fb;
        char            dev_name[32];
        unsigned int    fb_size;
        unsigned int    chip_id;
index 6cb54f8..116e808 100644 (file)
@@ -288,22 +288,25 @@ static int epson1355fb_blank(int blank_mode, struct fb_info *info)
        struct epson1355_par *par = info->par;
 
        switch (blank_mode) {
-       case VESA_NO_BLANKING:
+       case FB_BLANK_UNBLANKING:
+       case FB_BLANK_NORMAL:
                lcd_enable(par, 1);
                backlight_enable(1);
                break;
-       case VESA_VSYNC_SUSPEND:
-       case VESA_HSYNC_SUSPEND:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
                backlight_enable(0);
                break;
-       case VESA_POWERDOWN:
+       case FB_BLANK_POWERDOWN:
                backlight_enable(0);
                lcd_enable(par, 0);
                break;
        default:
                return -EINVAL;
        }
-       return 0;
+
+       /* let fbcon do a soft blank for us */
+       return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
 }
 
 /* ------------------------------------------------------------------------- */
index 8b3bbe0..4fec33d 100644 (file)
@@ -51,6 +51,8 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
        if (size)
                info->par = p + fb_info_size;
 
+       info->device = dev;
+
        return info;
 #undef PADDING
 #undef BYTES_PER_LONG
index 349499e..10cd050 100644 (file)
@@ -676,7 +676,7 @@ ffb_blank(int blank, struct fb_info *info)
        FFBWait(par);
 
        switch (blank) {
-       case 0: /* Unblanking */
+       case FB_BLANK_UNBLANK: /* Unblanking */
                upa_writel(0x6000, &dac->type);
                tmp = (upa_readl(&dac->value) | 0x1);
                upa_writel(0x6000, &dac->type);
@@ -684,10 +684,10 @@ ffb_blank(int blank, struct fb_info *info)
                par->flags &= ~FFB_FLAG_BLANKED;
                break;
 
-       case 1: /* Normal blanking */
-       case 2: /* VESA blank (vsync off) */
-       case 3: /* VESA blank (hsync off) */
-       case 4: /* Poweroff */
+       case FB_BLANK_NORMAL: /* Normal blanking */
+       case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+       case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+       case FB_BLANK_POWERDOWN: /* Poweroff */
                upa_writel(0x6000, &dac->type);
                tmp = (upa_readl(&dac->value) & ~0x1);
                upa_writel(0x6000, &dac->type);
@@ -969,7 +969,6 @@ static void ffb_init_one(int node, int parent)
                           FBINFO_HWACCEL_IMAGEBLIT);
        all->info.fbops = &ffb_ops;
        all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF;
-       all->info.currcon = -1;
        all->info.par = &all->par;
        all->info.pseudo_palette = all->pseudo_palette;
 
index 3adb65d..a076328 100644 (file)
@@ -2,7 +2,7 @@
  *  linux/drivers/video/fm2fb.c -- BSC FrameMaster II/Rainbow II frame buffer
  *                                device
  *
- *     Copyright (C) 1998 Steffen A. Mork (mork@ls7.cs.uni-dortmund.de)
+ *     Copyright (C) 1998 Steffen A. Mork (linux-dev@morknet.de)
  *     Copyright (C) 1999 Geert Uytterhoeven
  *
  *  Written for 2.0.x by Steffen A. Mork
@@ -292,18 +292,7 @@ static int __devinit fm2fb_probe(struct zorro_dev *z,
        return 0;
 }
 
-int __init fm2fb_setup(char *options);
-
-int __init fm2fb_init(void)
-{
-       char *option = NULL;
-
-       if (fb_get_options("fm2fb", &option))
-               return -ENODEV;
-       fm2fb_setup(option);
-       return zorro_register_driver(&fm2fb_driver);
-}
-
+int __init fm2fb_setup(char *options)
 {
        char *this_opt;
 
@@ -319,5 +308,15 @@ int __init fm2fb_init(void)
        return 0;
 }
 
+int __init fm2fb_init(void)
+{
+       char *option = NULL;
+
+       if (fb_get_options("fm2fb", &option))
+               return -ENODEV;
+       fm2fb_setup(option);
+       return zorro_register_driver(&fm2fb_driver);
+}
+
 module_init(fm2fb_init);
 MODULE_LICENSE("GPL");
index 1dfc1d6..087a3bc 100644 (file)
@@ -384,11 +384,11 @@ static int gbefb_blank(int blank, struct fb_info *info)
 {
        /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
        switch (blank) {
-       case 0:         /* unblank */
+       case FB_BLANK_UNBLANK:          /* unblank */
                gbe_turn_on();
                break;
 
-       case 1:         /* blank */
+       case FB_BLANK_NORMAL:           /* blank */
                gbe_turn_off();
                break;
 
@@ -1018,8 +1018,8 @@ static int gbefb_mmap(struct fb_info *info, struct file *file,
                else
                        phys_size = TILE_SIZE - offset;
 
-               if (remap_page_range
-                   (vma, addr, phys_addr, phys_size, vma->vm_page_prot))
+               if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT,
+                                               phys_size, vma->vm_page_prot))
                        return -EAGAIN;
 
                offset = 0;
@@ -1084,9 +1084,9 @@ int __init gbefb_init(void)
        int i, ret = 0;
 
 #ifndef MODULE
-       char *option = NULL;
+       char *options = NULL;
 
-       if (fb_get_options("gbefb", &option))
+       if (fb_get_options("gbefb", &options))
                return -ENODEV;
        gbefb_setup(options);
 #endif
@@ -1140,7 +1140,6 @@ int __init gbefb_init(void)
        for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
                gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
 
-       fb_info.currcon = -1;
        fb_info.fbops = &gbefb_ops;
        fb_info.pseudo_palette = pseudo_palette;
        fb_info.flags = FBINFO_DEFAULT;
index 9405d71..e97fe84 100644 (file)
@@ -1,6 +1,8 @@
 /*
  *     HP300 Topcat framebuffer support (derived from macfb of all things)
  *     Phil Blundell <philb@gnu.org> 1998
+ *     DIO-II, colour map and Catseye support by
+ *     Kars de Jong <jongk@linux-m68k.org>, May 2004.
  */
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/fb.h>
 #include <linux/dio.h>
+
 #include <asm/io.h>
-#include <asm/blinken.h>
-#include <asm/hwtest.h>
+#include <asm/uaccess.h>
 
-static struct fb_info fb_info;
+static struct fb_info fb_info = {
+       .fix = {
+               .id             = "HP300 ",
+               .type           = FB_TYPE_PACKED_PIXELS,
+               .visual         = FB_VISUAL_PSEUDOCOLOR,
+               .accel          = FB_ACCEL_NONE,
+       }
+};
 
-unsigned long fb_regs;
-unsigned char fb_bitmask;
+static unsigned long fb_regs;
+static unsigned char fb_bitmask;
 
+#define TC_NBLANK      0x4080
 #define TC_WEN         0x4088
 #define TC_REN         0x408c
 #define TC_FBEN                0x4090
-#define TC_NBLANK      0x4080
+#define TC_PRR         0x40ea
+
+/* These defines match the X window system */
+#define RR_CLEAR       0x0
+#define RR_COPY                0x3
+#define RR_NOOP                0x5
+#define RR_XOR         0x6
+#define RR_INVERT      0xa
+#define RR_COPYINVERTED 0xc
+#define RR_SET         0xf
 
 /* blitter regs */
 #define BUSY           0x4044
@@ -40,129 +59,250 @@ unsigned char fb_bitmask;
 #define WWIDTH         0x4102
 #define WMOVE          0x409c
 
-static struct fb_fix_screeninfo hpfb_fix __initdata = {
-       .id             = "HP300 Topcat",
-       .smem_len       = 1024*768,
-       .type           = FB_TYPE_PACKED_PIXELS,
-       .visual         = FB_VISUAL_PSEUDOCOLOR,
-       .line_length    = 1024,
-       .accel          = FB_ACCEL_NONE,
-};
-
 static struct fb_var_screeninfo hpfb_defined = {
-       .xres           = 1024,
-       .yres           = 768,
-       .xres_virtual   = 1024,
-       .yres_virtual   = 786,
-       .bits_per_pixel = 1,
-       .red            = {0,2,0},      /* R */
-       .green          = {0,2,0},      /* G */
-       .blue           = {0,2,0},      /* B */
+       .red            = {
+               .length = 8,
+       },
+       .green          = {
+               .length = 8,
+       },
+       .blue           = {
+               .length = 8,
+       },
        .activate       = FB_ACTIVATE_NOW,
-       .height         = 274,
-       .width          = 195,  /* 14" monitor */
-       .accel_flags    = FB_ACCEL_NONE,
+       .height         = -1,
+       .width          = -1,
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-/*
- * Set the palette.  This may not work on all boards but only experimentation 
- * will tell.
- * XXX Doesn't work at all.
- */
 static int hpfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                           unsigned blue, unsigned transp,
-                           struct fb_info *info)
+                         unsigned blue, unsigned transp,
+                         struct fb_info *info)
 {
+       /* use MSBs */
+       unsigned char _red  =red>>8;
+       unsigned char _green=green>>8;
+       unsigned char _blue =blue>>8;
+       unsigned char _regno=regno;
+
+       /*
+        *  Set a single color register. The values supplied are
+        *  already rounded down to the hardware's capabilities
+        *  (according to the entries in the `var' structure). Return
+        *  != 0 for invalid regno.
+        */
+
+       if (regno >= info->cmap.len)
+               return 1;
+       
        while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1);
-       out_be16(fb_regs + 0x60f0, 0);
-       out_be16(fb_regs + 0x60b8, regno);
-       out_be16(fb_regs + 0x60b2, red);
-       out_be16(fb_regs + 0x60b4, green);
-       out_be16(fb_regs + 0x60b6, blue);
+
+       out_be16(fb_regs + 0x60ba, 0xff);
+
+       out_be16(fb_regs + 0x60b2, _red);
+       out_be16(fb_regs + 0x60b4, _green);
+       out_be16(fb_regs + 0x60b6, _blue);
+       out_be16(fb_regs + 0x60b8, ~_regno);
        out_be16(fb_regs + 0x60f0, 0xff);
+
        udelay(100);
-       out_be16(fb_regs + 0x60ba, 0xffff);
+
+       while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1);
+       out_be16(fb_regs + 0x60b2, 0);
+       out_be16(fb_regs + 0x60b4, 0);
+       out_be16(fb_regs + 0x60b6, 0);
+       out_be16(fb_regs + 0x60b8, 0);
+
+       return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static int hpfb_blank(int blank, struct fb_info *info)
+{
+       out_8(fb_regs + TC_NBLANK, (blank ? 0x00 : fb_bitmask));
+
        return 0;
 }
 
-void hpfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 
+static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h, int rr)
 {
-       while (in_8(fb_regs + BUSY) & fb_bitmask);
-       out_8(fb_regs + WMRR, 0x3);
-       out_be16(fb_regs + SOURCE_X, area->sx);
-       out_be16(fb_regs + SOURCE_Y, area->sy);
-       out_be16(fb_regs + DEST_X, area->dx);
-       out_be16(fb_regs + DEST_Y, area->dy);
-       out_be16(fb_regs + WHEIGHT, area->height);
-       out_be16(fb_regs + WWIDTH, area->width);
+       if (rr >= 0) {
+               while (in_8(fb_regs + BUSY) & fb_bitmask)
+                       ;
+       }
+       out_8(fb_regs + TC_FBEN, fb_bitmask);
+       if (rr >= 0) {
+               out_8(fb_regs + TC_WEN, fb_bitmask);
+               out_8(fb_regs + WMRR, rr);
+       }
+       out_be16(fb_regs + SOURCE_X, x0);
+       out_be16(fb_regs + SOURCE_Y, y0);
+       out_be16(fb_regs + DEST_X, x1);
+       out_be16(fb_regs + DEST_Y, y1);
+       out_be16(fb_regs + WWIDTH, w);
+       out_be16(fb_regs + WHEIGHT, h);
        out_8(fb_regs + WMOVE, fb_bitmask);
 }
 
+static void hpfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 
+{
+       topcat_blit(area->sx, area->sy, area->dx, area->dy, area->width, area->height, RR_COPY);
+}
+
+static void hpfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
+{
+       u8 clr;
+
+       clr = region->color & 0xff;
+
+       while (in_8(fb_regs + BUSY) & fb_bitmask)
+               ;
+
+       /* Foreground */
+       out_8(fb_regs + TC_WEN, fb_bitmask & clr);
+       out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_SET : RR_INVERT));
+
+       /* Background */
+       out_8(fb_regs + TC_WEN, fb_bitmask & ~clr);
+       out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_CLEAR : RR_NOOP));
+
+       topcat_blit(region->dx, region->dy, region->dx, region->dy, region->width, region->height, -1);
+}
+
+static int hpfb_sync(struct fb_info *info)
+{
+       /*
+        * Since we also access the framebuffer directly, we have to wait
+        * until the block mover is finished
+        */
+       while (in_8(fb_regs + BUSY) & fb_bitmask)
+               ;
+
+       out_8(fb_regs + TC_WEN, fb_bitmask);
+       out_8(fb_regs + TC_PRR, RR_COPY);
+       out_8(fb_regs + TC_FBEN, fb_bitmask);
+
+       return 0;
+}
+
 static struct fb_ops hpfb_ops = {
        .owner          = THIS_MODULE,
        .fb_setcolreg   = hpfb_setcolreg,
-       .fb_fillrect    = cfb_fillrect,
+       .fb_blank       = hpfb_blank,
+       .fb_fillrect    = hpfb_fillrect,
        .fb_copyarea    = hpfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
        .fb_cursor      = soft_cursor,
+       .fb_sync        = hpfb_sync,
 };
 
-#define TOPCAT_FBOMSB  0x5d
-#define TOPCAT_FBOLSB  0x5f
+/* Common to all HP framebuffers */
+#define HPFB_FBWMSB    0x05    /* Frame buffer width           */
+#define HPFB_FBWLSB    0x07
+#define HPFB_FBHMSB    0x09    /* Frame buffer height          */
+#define HPFB_FBHLSB    0x0b
+#define HPFB_DWMSB     0x0d    /* Display width                */
+#define HPFB_DWLSB     0x0f
+#define HPFB_DHMSB     0x11    /* Display height               */
+#define HPFB_DHLSB     0x13
+#define HPFB_NUMPLANES 0x5b    /* Number of colour planes      */
+#define HPFB_FBOMSB    0x5d    /* Frame buffer offset          */
+#define HPFB_FBOLSB    0x5f
 
-int __init hpfb_init_one(unsigned long base)
+static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base)
 {
-       unsigned long fboff;
+       unsigned long fboff, fb_width, fb_height, fb_start;
 
-       if (fb_get_options("hpfb", NULL))
-               return -ENODEV;
+       fb_regs = virt_base;
+       fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB);
+
+       fb_info.fix.smem_start = (in_8(fb_regs + fboff) << 16);
 
-       fboff = (in_8(base + TOPCAT_FBOMSB) << 8) | in_8(base + TOPCAT_FBOLSB);
-
-       hpfb_fix.smem_start = 0xf0000000 | (in_8(base + fboff) << 16);
-       fb_regs = base;
-
-#if 0
-       /* This is the magic incantation NetBSD uses to make Catseye boards work. */
-       out_8(base+0x4800, 0);
-       out_8(base+0x4510, 0);
-       out_8(base+0x4512, 0);
-       out_8(base+0x4514, 0);
-       out_8(base+0x4516, 0);
-       out_8(base+0x4206, 0x90);
-#endif
-       /* 
+       if (phys_base >= DIOII_BASE) {
+               fb_info.fix.smem_start += phys_base;
+       }
+
+       if (DIO_SECID(fb_regs) != DIO_ID2_TOPCAT) {
+               /* This is the magic incantation the HP X server uses to make Catseye boards work. */
+               while (in_be16(fb_regs+0x4800) & 1)
+                       ;
+               out_be16(fb_regs+0x4800, 0);    /* Catseye status */
+               out_be16(fb_regs+0x4510, 0);    /* VB */
+               out_be16(fb_regs+0x4512, 0);    /* TCNTRL */
+               out_be16(fb_regs+0x4514, 0);    /* ACNTRL */
+               out_be16(fb_regs+0x4516, 0);    /* PNCNTRL */
+               out_be16(fb_regs+0x4206, 0x90); /* RUG Command/Status */
+               out_be16(fb_regs+0x60a2, 0);    /* Overlay Mask */
+               out_be16(fb_regs+0x60bc, 0);    /* Ram Select */
+       }
+
+       /*
+        *      Fill in the available video resolution
+        */
+       fb_width = (in_8(fb_regs + HPFB_FBWMSB) << 8) | in_8(fb_regs + HPFB_FBWLSB);
+       fb_info.fix.line_length = fb_width;
+       fb_height = (in_8(fb_regs + HPFB_FBHMSB) << 8) | in_8(fb_regs + HPFB_FBHLSB);
+       fb_info.fix.smem_len = fb_width * fb_height;
+       fb_start = (unsigned long)ioremap_writethrough(fb_info.fix.smem_start,
+                                                      fb_info.fix.smem_len);
+       hpfb_defined.xres = (in_8(fb_regs + HPFB_DWMSB) << 8) | in_8(fb_regs + HPFB_DWLSB);
+       hpfb_defined.yres = (in_8(fb_regs + HPFB_DHMSB) << 8) | in_8(fb_regs + HPFB_DHLSB);
+       hpfb_defined.xres_virtual = hpfb_defined.xres;
+       hpfb_defined.yres_virtual = hpfb_defined.yres;
+       hpfb_defined.bits_per_pixel = in_8(fb_regs + HPFB_NUMPLANES);
+
+       printk(KERN_INFO "hpfb: framebuffer at 0x%lx, mapped to 0x%lx, size %dk\n",
+              fb_info.fix.smem_start, fb_start, fb_info.fix.smem_len/1024);
+       printk(KERN_INFO "hpfb: mode is %dx%dx%d, linelength=%d\n",
+              hpfb_defined.xres, hpfb_defined.yres, hpfb_defined.bits_per_pixel, fb_info.fix.line_length);
+
+       /*
         *      Give the hardware a bit of a prod and work out how many bits per
         *      pixel are supported.
         */
-       
-       out_8(base + TC_WEN, 0xff);
-       out_8(base + TC_FBEN, 0xff);
-       out_8(hpfb_fix.smem_start, 0xff);
-       fb_bitmask = in_8(hpfb_fix.smem_start);
+       out_8(fb_regs + TC_WEN, 0xff);
+       out_8(fb_regs + TC_PRR, RR_COPY);
+       out_8(fb_regs + TC_FBEN, 0xff);
+       out_8(fb_start, 0xff);
+       fb_bitmask = in_8(fb_start);
+       out_8(fb_start, 0);
 
        /*
         *      Enable reading/writing of all the planes.
         */
-       out_8(base + TC_WEN, fb_bitmask);
-       out_8(base + TC_REN, fb_bitmask);
-       out_8(base + TC_FBEN, fb_bitmask);
-       out_8(base + TC_NBLANK, 0x1);
+       out_8(fb_regs + TC_WEN, fb_bitmask);
+       out_8(fb_regs + TC_PRR, RR_COPY);
+       out_8(fb_regs + TC_REN, fb_bitmask);
+       out_8(fb_regs + TC_FBEN, fb_bitmask);
+
+       /*
+        *      Clear the screen.
+        */
+       topcat_blit(0, 0, 0, 0, fb_width, fb_height, RR_CLEAR);
 
        /*
         *      Let there be consoles..
         */
+       if (DIO_SECID(fb_regs) == DIO_ID2_TOPCAT)
+               strcat(fb_info.fix.id, "Topcat");
+       else
+               strcat(fb_info.fix.id, "Catseye");
        fb_info.fbops = &hpfb_ops;
        fb_info.flags = FBINFO_DEFAULT;
        fb_info.var   = hpfb_defined;
-       fb_info.fix   = hpfb_fix;
-       fb_info.screen_base = (char *)hpfb_fix.smem_start;      // FIXME
+       fb_info.screen_base = (char *)fb_start;
 
-       fb_alloc_cmap(&fb_info.cmap, 256, 0);
+       fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
 
-       if (register_framebuffer(&fb_info) < 0)
+       if (register_framebuffer(&fb_info) < 0) {
+               fb_dealloc_cmap(&fb_info.cmap);
                return 1;
+       }
+
+       printk(KERN_INFO "fb%d: %s frame buffer device\n",
+              fb_info.node, fb_info.fix.id);
+
        return 0;
 }
 
@@ -177,42 +317,100 @@ int __init hpfb_init_one(unsigned long base)
 /* 
  * Initialise the framebuffer
  */
+static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_id * ent)
+{
+       unsigned long paddr, vaddr;
+
+       paddr = d->resource.start;
+       if (!request_mem_region(d->resource.start, d->resource.end - d->resource.start, d->name))
+                return -EBUSY;
+
+       if (d->scode >= DIOII_SCBASE) {
+               vaddr = (unsigned long)ioremap(paddr, d->resource.end - d->resource.start);
+       } else {
+               vaddr = paddr + DIO_VIRADDRBASE;
+       }
+       printk(KERN_INFO "Topcat found at DIO select code %d "
+              "(secondary id %02x)\n", d->scode, (d->id >> 8) & 0xff);
+       if (hpfb_init_one(paddr, vaddr)) {
+               if (d->scode >= DIOII_SCBASE)
+                       iounmap((void *)vaddr);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void __devexit hpfb_remove_one(struct dio_dev *d)
+{
+       unregister_framebuffer(&fb_info);
+       if (d->scode >= DIOII_SCBASE)
+               iounmap((void *)fb_regs);
+        release_mem_region(d->resource.start, d->resource.end - d->resource.start);
+}
+
+static struct dio_device_id hpfb_dio_tbl[] = {
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_LRCATSEYE) },
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRCCATSEYE) },
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRMCATSEYE) },
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_TOPCAT) },
+    { 0 }
+};
+
+static struct dio_driver hpfb_driver = {
+    .name      = "hpfb",
+    .id_table  = hpfb_dio_tbl,
+    .probe     = hpfb_dio_probe,
+    .remove    = __devexit_p(hpfb_remove_one),
+};
 
 int __init hpfb_init(void)
 {
        unsigned int sid;
+       mm_segment_t fs;
+       unsigned char i;
+       int err;
 
        /* Topcats can be on the internal IO bus or real DIO devices.
-        * The internal variant sits at 0xf0560000; it has primary
+        * The internal variant sits at 0x560000; it has primary
         * and secondary ID registers just like the DIO version.
         * So we merge the two detection routines.
         *
         * Perhaps this #define should be in a global header file:
         * I believe it's common to all internal fbs, not just topcat.
         */
-#define INTFBADDR 0xf0560000
+#define INTFBVADDR 0xf0560000
+#define INTFBPADDR 0x560000
 
-       if (hwreg_present((void *)INTFBADDR) && 
-          (DIO_ID(INTFBADDR) == DIO_ID_FBUFFER) &&
-           topcat_sid_ok(sid = DIO_SECID(INTFBADDR))) {
-               printk("Internal Topcat found (secondary id %02x)\n", sid); 
-               hpfb_init_one(INTFBADDR);
-       } else {
-               int sc = dio_find(DIO_ID_FBUFFER);
+       if (!MACH_IS_HP300)
+               return -ENXIO;
+
+       if (fb_get_options("hpfb", NULL))
+               return -ENODEV;
 
-               if (sc) {
-                       unsigned long addr = (unsigned long)dio_scodetoviraddr(sc);
-                       unsigned int sid = DIO_SECID(addr);
+       dio_module_init(&hpfb_driver);
 
-                       if (topcat_sid_ok(sid)) {
-                               printk("Topcat found at DIO select code %02x "
-                                       "(secondary id %02x)\n", sc, sid);
-                               hpfb_init_one(addr);
-                       }
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       err = get_user(i, (unsigned char *)INTFBVADDR + DIO_IDOFF);
+       set_fs(fs);
+
+       if (!err && (i == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBVADDR))) {
+               if (!request_mem_region(INTFBPADDR, DIO_DEVSIZE, "Internal Topcat"))
+                       return -EBUSY;
+               printk(KERN_INFO "Internal Topcat found (secondary id %02x)\n", sid);
+               if (hpfb_init_one(INTFBPADDR, INTFBVADDR)) {
+                       return -ENOMEM;
                }
        }
        return 0;
 }
 
+void __exit hpfb_cleanup_module(void)
+{
+       dio_unregister_driver(&hpfb_driver);
+}
+
 module_init(hpfb_init);
+module_exit(hpfb_cleanup_module);
+
 MODULE_LICENSE("GPL");
index 68b6423..fe3b757 100644 (file)
 #define HAS_ACCELERATION            2
 #define ALWAYS_SYNC                 4
 #define LOCKUP                      8
+#define USE_HWCUR                  16
 
 struct gtt_data {
        struct agp_memory *i810_fb_memory;
@@ -222,7 +223,7 @@ struct mode_registers {
 
 struct heap_data {
         unsigned long physical;
-       __u8 *virtual;
+       __u8 __iomem *virtual;
        u32 offset;
        u32 size;
 };     
@@ -251,12 +252,10 @@ struct i810fb_par {
        struct heap_data         iring;
        struct heap_data         cursor_heap;
        struct vgastate          state;
-       drm_agp_t                *drm_agp;
        atomic_t                 use_count;
        u32 pseudo_palette[17];
-       u32 pci_state[16];
        unsigned long mmio_start_phys;
-       u8 *mmio_start_virtual;
+       u8 __iomem *mmio_start_virtual;
        u32 pitch;
        u32 pixconf;
        u32 watermark;
index 71f649f..9921db8 100644 (file)
@@ -32,7 +32,7 @@ extern void flush_cache(void);
 /************************************************************/
 
 /* BLT Engine Routines */
-static inline void i810_report_error(u8 *mmio)
+static inline void i810_report_error(u8 __iomem *mmio)
 {
        printk("IIR     : 0x%04x\n"
               "EIR     : 0x%04x\n"
@@ -59,7 +59,7 @@ static inline int wait_for_space(struct fb_info *info, u32 space)
 {
        struct i810fb_par *par = (struct i810fb_par *) info->par;
        u32 head, count = WAIT_COUNT, tail;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        tail = par->cur_tail;
        while (count--) {
@@ -89,7 +89,7 @@ static inline int wait_for_space(struct fb_info *info, u32 space)
 static inline int wait_for_engine_idle(struct fb_info *info)
 {
        struct i810fb_par *par = (struct i810fb_par *) info->par;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
        int count = WAIT_COUNT;
 
        if (wait_for_space(info, par->iring.size)) /* flush */
@@ -133,7 +133,7 @@ static inline u32 begin_iring(struct fb_info *info, u32 space)
  */
 static inline void end_iring(struct i810fb_par *par)
 {
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        i810_writel(IRING, mmio, par->cur_tail);
 }
@@ -326,7 +326,7 @@ static inline void load_front(int offset, struct fb_info *info)
 static inline void i810fb_iring_enable(struct i810fb_par *par, u32 mode)
 {
        u32 tmp;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        tmp = i810_readl(IRING + 12, mmio);
        if (mode == OFF) 
@@ -451,7 +451,7 @@ int i810fb_sync(struct fb_info *info)
 void i810fb_load_front(u32 offset, struct fb_info *info)
 {
        struct i810fb_par *par = (struct i810fb_par *) info->par;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        if (!info->var.accel_flags || par->dev_flags & LOCKUP)
                i810_writel(DPLYBASE, mmio, par->fb.physical + offset);
@@ -472,7 +472,7 @@ void i810fb_init_ringbuffer(struct fb_info *info)
 {
        struct i810fb_par *par = (struct i810fb_par *) info->par;
        u32 tmp1, tmp2;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
        
        wait_for_engine_idle(info);
        i810fb_iring_enable(par, OFF);
index 6acde25..40f9826 100644 (file)
@@ -121,7 +121,7 @@ static int dcolor     __initdata = 0;
  * DESCRIPTION:
  * Blanks/unblanks the display
  */
-static void i810_screen_off(u8 *mmio, u8 mode)
+static void i810_screen_off(u8 __iomem *mmio, u8 mode)
 {
        u32 count = WAIT_COUNT;
        u8 val;
@@ -145,7 +145,7 @@ static void i810_screen_off(u8 *mmio, u8 mode)
  * Turns off DRAM refresh.  Must be off for only 2 vsyncs
  * before data becomes corrupt
  */
-static void i810_dram_off(u8 *mmio, u8 mode)
+static void i810_dram_off(u8 __iomem *mmio, u8 mode)
 {
        u8 val;
 
@@ -164,7 +164,7 @@ static void i810_dram_off(u8 *mmio, u8 mode)
  * The IBM VGA standard allows protection of certain VGA registers.  
  * This will  protect or unprotect them. 
  */
-static void i810_protect_regs(u8 *mmio, int mode)
+static void i810_protect_regs(u8 __iomem *mmio, int mode)
 {
        u8 reg;
 
@@ -187,7 +187,7 @@ static void i810_protect_regs(u8 *mmio, int mode)
 static void i810_load_pll(struct i810fb_par *par)
 {
        u32 tmp1, tmp2;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
        
        tmp1 = par->regs.M | par->regs.N << 16;
        tmp2 = i810_readl(DCLK_2D, mmio);
@@ -212,7 +212,7 @@ static void i810_load_pll(struct i810fb_par *par)
  */
 static void i810_load_vga(struct i810fb_par *par)
 {      
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        /* interlace */
        i810_writeb(CR_INDEX_CGA, mmio, CR70);
@@ -255,7 +255,7 @@ static void i810_load_vga(struct i810fb_par *par)
  */
 static void i810_load_vgax(struct i810fb_par *par)
 {
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        i810_writeb(CR_INDEX_CGA, mmio, CR30);
        i810_writeb(CR_DATA_CGA, mmio, par->regs.cr30);
@@ -281,7 +281,8 @@ static void i810_load_vgax(struct i810fb_par *par)
 static void i810_load_2d(struct i810fb_par *par)
 {
        u32 tmp;
-       u8 tmp8, *mmio = par->mmio_start_virtual;
+       u8 tmp8;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        i810_writel(FW_BLC, mmio, par->watermark); 
        tmp = i810_readl(PIXCONF, mmio);
@@ -301,7 +302,7 @@ static void i810_load_2d(struct i810fb_par *par)
  * i810_hires - enables high resolution mode
  * @mmio: address of register space
  */
-static void i810_hires(u8 *mmio)
+static void i810_hires(u8 __iomem *mmio)
 {
        u8 val;
        
@@ -321,7 +322,8 @@ static void i810_hires(u8 *mmio)
 static void i810_load_pitch(struct i810fb_par *par)
 {
        u32 tmp, pitch;
-       u8 val, *mmio = par->mmio_start_virtual;
+       u8 val;
+       u8 __iomem *mmio = par->mmio_start_virtual;
                        
        pitch = par->pitch >> 3;
        i810_writeb(SR_INDEX, mmio, SR01);
@@ -351,9 +353,10 @@ static void i810_load_pitch(struct i810fb_par *par)
  */
 static void i810_load_color(struct i810fb_par *par)
 {
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
        u32 reg1;
        u16 reg2;
+
        reg1 = i810_readl(PIXCONF, mmio) & ~(0xF0000 | 1 << 27);
        reg2 = i810_readw(BLTCNTL, mmio) & ~0x30;
 
@@ -372,7 +375,7 @@ static void i810_load_color(struct i810fb_par *par)
  */
 static void i810_load_regs(struct i810fb_par *par)
 {
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        i810_screen_off(mmio, OFF);
        i810_protect_regs(mmio, OFF);
@@ -390,7 +393,7 @@ static void i810_load_regs(struct i810fb_par *par)
 }
 
 static void i810_write_dac(u8 regno, u8 red, u8 green, u8 blue,
-                         u8 *mmio)
+                         u8 __iomem *mmio)
 {
        i810_writeb(CLUT_INDEX_WRITE, mmio, regno);
        i810_writeb(CLUT_DATA, mmio, red);
@@ -399,7 +402,7 @@ static void i810_write_dac(u8 regno, u8 red, u8 green, u8 blue,
 }
 
 static void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue,
-                         u8 *mmio)
+                         u8 __iomem *mmio)
 {
        i810_writeb(CLUT_INDEX_READ, mmio, regno);
        *red = i810_readb(CLUT_DATA, mmio);
@@ -413,7 +416,7 @@ static void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue,
 static void i810_restore_pll(struct i810fb_par *par)
 {
        u32 tmp1, tmp2;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
        
        tmp1 = par->hw_state.dclk_2d;
        tmp2 = i810_readl(DCLK_2D, mmio);
@@ -433,7 +436,7 @@ static void i810_restore_pll(struct i810fb_par *par)
 static void i810_restore_dac(struct i810fb_par *par)
 {
        u32 tmp1, tmp2;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        tmp1 = par->hw_state.pixconf;
        tmp2 = i810_readl(PIXCONF, mmio);
@@ -444,7 +447,8 @@ static void i810_restore_dac(struct i810fb_par *par)
 
 static void i810_restore_vgax(struct i810fb_par *par)
 {
-       u8 i, j, *mmio = par->mmio_start_virtual;
+       u8 i, j;
+       u8 __iomem *mmio = par->mmio_start_virtual;
        
        for (i = 0; i < 4; i++) {
                i810_writeb(CR_INDEX_CGA, mmio, CR30+i);
@@ -477,7 +481,8 @@ static void i810_restore_vgax(struct i810fb_par *par)
 
 static void i810_restore_vga(struct i810fb_par *par)
 {
-       u8 i, *mmio = par->mmio_start_virtual;
+       u8 i;
+       u8 __iomem *mmio = par->mmio_start_virtual;
        
        for (i = 0; i < 10; i++) {
                i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);
@@ -491,7 +496,8 @@ static void i810_restore_vga(struct i810fb_par *par)
 
 static void i810_restore_addr_map(struct i810fb_par *par)
 {
-       u8 tmp, *mmio = par->mmio_start_virtual;
+       u8 tmp;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        i810_writeb(GR_INDEX, mmio, GR10);
        tmp = i810_readb(GR_DATA, mmio);
@@ -505,7 +511,7 @@ static void i810_restore_2d(struct i810fb_par *par)
 {
        u32 tmp_long;
        u16 tmp_word;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        tmp_word = i810_readw(BLTCNTL, mmio);
        tmp_word &= ~(3 << 4); 
@@ -534,7 +540,7 @@ static void i810_restore_2d(struct i810fb_par *par)
 
 static void i810_restore_vga_state(struct i810fb_par *par)
 {
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        i810_screen_off(mmio, OFF);
        i810_protect_regs(mmio, OFF);
@@ -556,7 +562,8 @@ static void i810_restore_vga_state(struct i810fb_par *par)
 
 static void i810_save_vgax(struct i810fb_par *par)
 {
-       u8 i, *mmio = par->mmio_start_virtual;
+       u8 i;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        for (i = 0; i < 4; i++) {
                i810_writeb(CR_INDEX_CGA, mmio, CR30 + i);
@@ -579,7 +586,8 @@ static void i810_save_vgax(struct i810fb_par *par)
 
 static void i810_save_vga(struct i810fb_par *par)
 {
-       u8 i, *mmio = par->mmio_start_virtual;
+       u8 i;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        for (i = 0; i < 10; i++) {
                i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);
@@ -593,7 +601,7 @@ static void i810_save_vga(struct i810fb_par *par)
 
 static void i810_save_2d(struct i810fb_par *par)
 {
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        par->hw_state.dclk_2d = i810_readl(DCLK_2D, mmio);
        par->hw_state.dclk_1d = i810_readl(DCLK_1D, mmio);
@@ -716,7 +724,7 @@ static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p)
  * Description:
  * Shows or hides the hardware cursor
  */
-void i810_enable_cursor(u8 *mmio, int mode)
+void i810_enable_cursor(u8 __iomem *mmio, int mode)
 {
        u32 temp;
        
@@ -729,7 +737,7 @@ void i810_enable_cursor(u8 *mmio, int mode)
 
 static void i810_reset_cursor_image(struct i810fb_par *par)
 {
-       u8 *addr = par->cursor_heap.virtual;
+       u8 __iomem *addr = par->cursor_heap.virtual;
        int i, j;
 
        for (i = 64; i--; ) {
@@ -744,7 +752,7 @@ static void i810_reset_cursor_image(struct i810fb_par *par)
 static void i810_load_cursor_image(int width, int height, u8 *data,
                                   struct i810fb_par *par)
 {
-       u8 *addr = par->cursor_heap.virtual;
+       u8 __iomem *addr = par->cursor_heap.virtual;
        int i, j, w = width/8;
        int mod = width % 8, t_mask, d_mask;
        
@@ -766,8 +774,8 @@ static void i810_load_cursor_image(int width, int height, u8 *data,
 static void i810_load_cursor_colors(int fg, int bg, struct fb_info *info)
 {
        struct i810fb_par *par = (struct i810fb_par *) info->par;
-       u8 *mmio = par->mmio_start_virtual, temp;
-       u8 red, green, blue, trans;
+       u8 __iomem *mmio = par->mmio_start_virtual;
+       u8 red, green, blue, trans, temp;
 
        i810fb_getcolreg(bg, &red, &green, &blue, &trans, info);
 
@@ -796,7 +804,7 @@ static void i810_load_cursor_colors(int fg, int bg, struct fb_info *info)
  */
 static void i810_init_cursor(struct i810fb_par *par)
 {
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        i810_enable_cursor(mmio, OFF);
        i810_writel(CURBASE, mmio, par->cursor_heap.physical);
@@ -1124,7 +1132,8 @@ static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue,
                            u8 *transp, struct fb_info *info)
 {
        struct i810fb_par *par = (struct i810fb_par *) info->par;
-       u8 *mmio = par->mmio_start_virtual, temp;
+       u8 __iomem *mmio = par->mmio_start_virtual;
+       u8 temp;
 
        if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
                if ((info->var.green.length == 5 && regno > 31) ||
@@ -1167,7 +1176,7 @@ static int i810fb_open(struct fb_info *info, int user)
        if (count == 0) {
                memset(&par->state, 0, sizeof(struct vgastate));
                par->state.flags = VGA_SAVE_CMAP;
-               par->state.vgabase = (caddr_t) par->mmio_start_virtual;
+               par->state.vgabase = par->mmio_start_virtual;
                save_vga(&par->state);
 
                i810_save_vga_state(par);
@@ -1203,7 +1212,8 @@ static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green,
                            struct fb_info *info)
 {
        struct i810fb_par *par = (struct i810fb_par *) info->par;
-       u8 *mmio = par->mmio_start_virtual, temp;
+       u8 __iomem *mmio = par->mmio_start_virtual;
+       u8 temp;
        int i;
 
        if (regno > 255) return 1;
@@ -1308,28 +1318,33 @@ static int i810fb_pan_display(struct fb_var_screeninfo *var,
 static int i810fb_blank (int blank_mode, struct fb_info *info)
 {
        struct i810fb_par *par = (struct i810fb_par *) info->par;
-       u8 *mmio = par->mmio_start_virtual;
+       u8 __iomem *mmio = par->mmio_start_virtual;
        int mode = 0, pwr, scr_off = 0;
        
        pwr = i810_readl(PWR_CLKC, mmio);
 
-       switch(blank_mode) {
-       case VESA_NO_BLANKING:
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
                mode = POWERON;
                pwr |= 1;
                scr_off = ON;
                break;
-       case VESA_VSYNC_SUSPEND:
+       case FB_BLANK_NORMAL:
+               mode = POWERON;
+               pwr |= 1;
+               scr_off = OFF;
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
                mode = STANDBY;
                pwr |= 1;
                scr_off = OFF;
                break;
-       case VESA_HSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
                mode = SUSPEND;
                pwr |= 1;
                scr_off = OFF;
                break;
-       case VESA_POWERDOWN:
+       case FB_BLANK_POWERDOWN:
                mode = POWERDOWN;
                pwr &= ~1;
                scr_off = OFF;
@@ -1337,9 +1352,11 @@ static int i810fb_blank (int blank_mode, struct fb_info *info)
        default:
                return -EINVAL; 
        }
+
        i810_screen_off(mmio, scr_off);
        i810_writel(HVSYNC, mmio, mode);
        i810_writel(PWR_CLKC, mmio, pwr);
+
        return 0;
 }
 
@@ -1391,9 +1408,10 @@ static int i810fb_check_var(struct fb_var_screeninfo *var,
 static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
        struct i810fb_par *par = (struct i810fb_par *)info->par;
-       u8 *mmio = par->mmio_start_virtual;     
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
-       if (!info->var.accel_flags || par->dev_flags & LOCKUP) 
+       if (!(par->dev_flags & USE_HWCUR) || !info->var.accel_flags ||
+           par->dev_flags & LOCKUP)
                return soft_cursor(info, cursor);
 
        if (cursor->image.width > 64 || cursor->image.height > 64)
@@ -1406,62 +1424,50 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 
        i810_enable_cursor(mmio, OFF);
 
-       if (cursor->set & FB_CUR_SETHOT)
-               info->cursor.hot = cursor->hot;
-       
        if (cursor->set & FB_CUR_SETPOS) {
                u32 tmp;
 
-               info->cursor.image.dx = cursor->image.dx;
-               info->cursor.image.dy = cursor->image.dy;
-               tmp = (info->cursor.image.dx - info->var.xoffset) & 0xffff;
-               tmp |= (info->cursor.image.dy - info->var.yoffset) << 16;
+               tmp = (cursor->image.dx - info->var.xoffset) & 0xffff;
+               tmp |= (cursor->image.dy - info->var.yoffset) << 16;
                i810_writel(CURPOS, mmio, tmp);
        }
 
-       if (cursor->set & FB_CUR_SETSIZE) {
+       if (cursor->set & FB_CUR_SETSIZE)
                i810_reset_cursor_image(par);
-               info->cursor.image.height = cursor->image.height;
-               info->cursor.image.width = cursor->image.width;
-       }
 
-       if (cursor->set & FB_CUR_SETCMAP) {
+       if (cursor->set & FB_CUR_SETCMAP)
                i810_load_cursor_colors(cursor->image.fg_color,
                                        cursor->image.bg_color,
                                        info);
-               info->cursor.image.fg_color = cursor->image.fg_color;
-               info->cursor.image.bg_color = cursor->image.bg_color;
 
-       }
-
-       if (cursor->set & (FB_CUR_SETSHAPE)) {
-               int size = ((info->cursor.image.width + 7) >> 3) * 
-                       info->cursor.image.height;
+       if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+               int size = ((cursor->image.width + 7) >> 3) *
+                       cursor->image.height;
                int i;
                u8 *data = kmalloc(64 * 8, GFP_KERNEL);
 
                if (data == NULL)
                        return -ENOMEM;
-               info->cursor.image.data = cursor->image.data;
 
-               switch (info->cursor.rop) {
+               switch (cursor->rop) {
                case ROP_XOR:
                        for (i = 0; i < size; i++)
-                               data[i] = info->cursor.image.data[i] ^ info->cursor.mask[i];
+                               data[i] = cursor->image.data[i] ^ cursor->mask[i];
                        break;
                case ROP_COPY:
                default:
                        for (i = 0; i < size; i++)
-                               data[i] = info->cursor.image.data[i] & info->cursor.mask[i];
+                               data[i] = cursor->image.data[i] & cursor->mask[i];
                        break;
                }
-               i810_load_cursor_image(info->cursor.image.width, 
-                                      info->cursor.image.height, data,
+
+               i810_load_cursor_image(cursor->image.width,
+                                      cursor->image.height, data,
                                       par);
                kfree(data);
        }
 
-       if (info->cursor.enable)
+       if (cursor->enable)
                i810_enable_cursor(mmio, ON);
 
        return 0;
@@ -1513,11 +1519,11 @@ static int i810fb_suspend(struct pci_dev *dev, u32 state)
        info->fbops->fb_blank(blank, info);
 
        if (!prev_state) { 
-               par->drm_agp->unbind_memory(par->i810_gtt.i810_fb_memory);
-               par->drm_agp->unbind_memory(par->i810_gtt.i810_cursor_memory);
+               agp_unbind_memory(par->i810_gtt.i810_fb_memory);
+               agp_unbind_memory(par->i810_gtt.i810_cursor_memory);
                pci_disable_device(dev);
        }
-       pci_save_state(dev, par->pci_state);
+       pci_save_state(dev);
        pci_set_power_state(dev, state);
 
        return 0;
@@ -1531,13 +1537,13 @@ static int i810fb_resume(struct pci_dev *dev)
        if (par->cur_state == 0)
                return 0;
 
-       pci_restore_state(dev, par->pci_state);
+       pci_restore_state(dev);
        pci_set_power_state(dev, 0);
        pci_enable_device(dev);
-       par->drm_agp->bind_memory(par->i810_gtt.i810_fb_memory, 
-                                 par->fb.offset);
-       par->drm_agp->bind_memory(par->i810_gtt.i810_cursor_memory, 
-                                 par->cursor_heap.offset);
+       agp_bind_memory(par->i810_gtt.i810_fb_memory,
+                       par->fb.offset);
+       agp_bind_memory(par->i810_gtt.i810_cursor_memory,
+                       par->cursor_heap.offset);
 
        info->fbops->fb_blank(VESA_NO_BLANKING, info);
 
@@ -1589,39 +1595,36 @@ static int __devinit i810_alloc_agp_mem(struct fb_info *info)
        i810_fix_offsets(par);
        size = par->fb.size + par->iring.size;
 
-       par->drm_agp = (drm_agp_t *) inter_module_get("drm_agp");
-       if (!par->drm_agp) {
-               printk("i810fb: cannot acquire agp\n");
+       if (agp_backend_acquire()) {
+               printk("i810fb_alloc_fbmem: cannot acquire agpgart\n");
                return -ENODEV;
        }
-       par->drm_agp->acquire(); 
-
        if (!(par->i810_gtt.i810_fb_memory = 
-             par->drm_agp->allocate_memory(size >> 12, AGP_NORMAL_MEMORY))) {
+             agp_allocate_memory(size >> 12, AGP_NORMAL_MEMORY))) {
                printk("i810fb_alloc_fbmem: can't allocate framebuffer "
                       "memory\n");
-               par->drm_agp->release();
+               agp_backend_release();
                return -ENOMEM;
        }
-       if (par->drm_agp->bind_memory(par->i810_gtt.i810_fb_memory, 
-                                     par->fb.offset)) {
+       if (agp_bind_memory(par->i810_gtt.i810_fb_memory,
+                           par->fb.offset)) {
                printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n");
-               par->drm_agp->release();
+               agp_backend_release();
                return -EBUSY;
        }       
        
        if (!(par->i810_gtt.i810_cursor_memory = 
-             par->drm_agp->allocate_memory(par->cursor_heap.size >> 12, 
-                                           AGP_PHYSICAL_MEMORY))) {
+             agp_allocate_memory(par->cursor_heap.size >> 12,
+                                 AGP_PHYSICAL_MEMORY))) {
                printk("i810fb_alloc_cursormem:  can't allocate" 
                       "cursor memory\n");
-               par->drm_agp->release();
+               agp_backend_release();
                return -ENOMEM;
        }
-       if (par->drm_agp->bind_memory(par->i810_gtt.i810_cursor_memory, 
+       if (agp_bind_memory(par->i810_gtt.i810_cursor_memory,
                            par->cursor_heap.offset)) {
                printk("i810fb_alloc_cursormem: cannot bind cursor memory\n");
-               par->drm_agp->release();
+               agp_backend_release();
                return -EBUSY;
        }       
 
@@ -1629,7 +1632,7 @@ static int __devinit i810_alloc_agp_mem(struct fb_info *info)
 
        i810_fix_pointers(par);
 
-       par->drm_agp->release();
+       agp_backend_release();
 
        return 0;
 }
@@ -1724,7 +1727,8 @@ static void __devinit i810_init_defaults(struct i810fb_par *par,
  */
 static void __devinit i810_init_device(struct i810fb_par *par)
 {
-       u8 reg, *mmio = par->mmio_start_virtual;
+       u8 reg;
+       u8 __iomem *mmio = par->mmio_start_virtual;
 
        if (mtrr) set_mtrr(par);
 
@@ -1855,27 +1859,20 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
        int i, err = -1, vfreq, hfreq, pixclock;
 
        i = 0;
-       if (!(info = kmalloc(sizeof(struct fb_info), GFP_KERNEL))) {
-               i810fb_release_resource(info, par);
-               return -ENOMEM;
-       }
-       memset(info, 0, sizeof(struct fb_info));
 
-       if(!(par = kmalloc(sizeof(struct i810fb_par), GFP_KERNEL))) {
-               i810fb_release_resource(info, par);
+       info = framebuffer_alloc(sizeof(struct i810fb_par), &dev->dev);
+       if (!info)
                return -ENOMEM;
-       }
-       memset(par, 0, sizeof(struct i810fb_par));
 
+       par = (struct i810fb_par *) info->par;
        par->dev = dev;
-       info->par = par;
 
-       if (!(info->pixmap.addr = kmalloc(64*1024, GFP_KERNEL))) {
+       if (!(info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL))) {
                i810fb_release_resource(info, par);
                return -ENOMEM;
        }
-       memset(info->pixmap.addr, 0, 64*1024);
-       info->pixmap.size = 64*1024;
+       memset(info->pixmap.addr, 0, 8*1024);
+       info->pixmap.size = 8*1024;
        info->pixmap.buf_align = 8;
        info->pixmap.flags = FB_PIXMAP_SYSTEM;
 
@@ -1941,38 +1938,30 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
 static void i810fb_release_resource(struct fb_info *info, 
                                    struct i810fb_par *par)
 {
-       if (par) {
-               unset_mtrr(par);
-               if (par->drm_agp) {
-                       drm_agp_t *agp = par->drm_agp;
-                       struct gtt_data *gtt = &par->i810_gtt;
-
-                       if (par->i810_gtt.i810_cursor_memory) 
-                               agp->free_memory(gtt->i810_cursor_memory);
-                       if (par->i810_gtt.i810_fb_memory) 
-                               agp->free_memory(gtt->i810_fb_memory);
-
-                       inter_module_put("drm_agp");
-                       par->drm_agp = NULL;
-               }
+       struct gtt_data *gtt = &par->i810_gtt;
+       unset_mtrr(par);
 
-               if (par->mmio_start_virtual) 
-                       iounmap(par->mmio_start_virtual);
-               if (par->aperture.virtual) 
-                       iounmap(par->aperture.virtual);
+       if (par->i810_gtt.i810_cursor_memory)
+               agp_free_memory(gtt->i810_cursor_memory);
+       if (par->i810_gtt.i810_fb_memory)
+               agp_free_memory(gtt->i810_fb_memory);
 
-               if (par->res_flags & FRAMEBUFFER_REQ)
-                       release_mem_region(par->aperture.physical, 
-                                          par->aperture.size);
-               if (par->res_flags & MMIO_REQ)
-                       release_mem_region(par->mmio_start_phys, MMIO_SIZE);
+       if (par->mmio_start_virtual)
+               iounmap(par->mmio_start_virtual);
+       if (par->aperture.virtual)
+               iounmap(par->aperture.virtual);
 
-               if (par->res_flags & PCI_DEVICE_ENABLED)
-                       pci_disable_device(par->dev); 
+       if (par->res_flags & FRAMEBUFFER_REQ)
+               release_mem_region(par->aperture.physical,
+                                  par->aperture.size);
+       if (par->res_flags & MMIO_REQ)
+               release_mem_region(par->mmio_start_phys, MMIO_SIZE);
+
+       if (par->res_flags & PCI_DEVICE_ENABLED)
+               pci_disable_device(par->dev);
+
+       framebuffer_release(info);
 
-               kfree(par);
-       }
-       kfree(info);
 }
 
 static void __exit i810fb_remove_pci(struct pci_dev *dev)
@@ -1995,10 +1984,7 @@ int __init i810fb_init(void)
                return -ENODEV;
        i810fb_setup(option);
 
-       if (pci_register_driver(&i810fb_driver) > 0)
-               return 0;
-       pci_unregister_driver(&i810fb_driver);
-       return -ENODEV;
+       return pci_register_driver(&i810fb_driver);
 }
 #endif 
 
@@ -2013,50 +1999,47 @@ int __init i810fb_init(void)
        hsync1 *= 1000;
        hsync2 *= 1000;
 
-       if (pci_register_driver(&i810fb_driver) > 0)
-               return 0;
-       pci_unregister_driver(&i810fb_driver);
-       return -ENODEV;
+       return pci_register_driver(&i810fb_driver);
 }
 
-MODULE_PARM(vram, "i");
+module_param(vram, int, 4);
 MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB" 
                 " (default=4)");
-MODULE_PARM(voffset, "i");
+module_param(voffset, int, 0);
 MODULE_PARM_DESC(voffset, "at what offset to place start of framebuffer "
                  "memory (0 to maximum aperture size), in MiB (default = 48)");
-MODULE_PARM(bpp, "i");
+module_param(bpp, int, 8);
 MODULE_PARM_DESC(bpp, "Color depth for display in bits per pixel"
                 " (default = 8)");
-MODULE_PARM(xres, "i");
+module_param(xres, int, 640);
 MODULE_PARM_DESC(xres, "Horizontal resolution in pixels (default = 640)");
-MODULE_PARM(yres, "i");
+module_param(yres, int, 480);
 MODULE_PARM_DESC(yres, "Vertical resolution in scanlines (default = 480)");
-MODULE_PARM(vyres, "i");
+module_param(vyres,int, 480);
 MODULE_PARM_DESC(vyres, "Virtual vertical resolution in scanlines"
                 " (default = 480)");
-MODULE_PARM(hsync1, "i");
+module_param(hsync1, int, 0);
 MODULE_PARM_DESC(hsync1, "Minimum horizontal frequency of monitor in KHz"
                 " (default = 31)");
-MODULE_PARM(hsync2, "i");
+module_param(hsync2, int, 0);
 MODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz"
                 " (default = 31)");
-MODULE_PARM(vsync1, "i");
+module_param(vsync1, int, 0);
 MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz"
                 " (default = 50)");
-MODULE_PARM(vsync2, "i");
+module_param(vsync2, int, 0);
 MODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz" 
                 " (default = 60)");
-MODULE_PARM(accel, "i");
+module_param(accel, bool, 0);
 MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)");
-MODULE_PARM(mtrr, "i");
+module_param(mtrr, bool, 0);
 MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)");
-MODULE_PARM(ext_vga, "i");
+module_param(ext_vga, bool, 0);
 MODULE_PARM_DESC(ext_vga, "Enable external VGA connector (default = 0)");
-MODULE_PARM(sync, "i");
+module_param(sync, bool, 0);
 MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing"
                 " (default = 0)");
-MODULE_PARM(dcolor, "i");
+module_param(dcolor, bool, 0);
 MODULE_PARM_DESC(dcolor, "use DirectColor visuals"
                 " (default = 0 = TrueColor)");
 
index dd6b16c..2da19ea 100644 (file)
@@ -262,8 +262,8 @@ static int igafb_mmap(struct fb_info *info, struct file *file,
                pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask);
                pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag;
 
-               if (remap_page_range(vma, vma->vm_start + page, map_offset,
-                                    map_size, vma->vm_page_prot))
+               if (remap_pfn_range(vma, vma->vm_start + page,
+                       map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot))
                        return -EAGAIN;
 
                page += map_size;
@@ -531,6 +531,7 @@ int __init igafb_init(void)
        info->var = default_var;
        info->fix = igafb_fix;
        info->pseudo_palette = (void *)(par + 1);
+       info->device = &pdev->dev;
 
        if (!iga_init(info, par)) {
                iounmap((void *)par->io_base);
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 */
index 11f70e3..7035ed1 100644 (file)
@@ -79,7 +79,7 @@ volatile u32 i,count=0; \
     for(i=0;i<X;i++) count++; \
 }
 
-u32 InitSDRAMRegisters(volatile STG4000REG pSTGReg, u32 dwSubSysID,
+u32 InitSDRAMRegisters(volatile STG4000REG __iomem *pSTGReg, u32 dwSubSysID,
                         u32 dwRevID)
 {
        u32 adwSDRAMArgCfg0[] = { 0xa0, 0x80, 0xa0, 0xa0, 0xa0 };
@@ -239,7 +239,7 @@ u32 ProgramClock(u32 refClock,
        return (ulBestClk);
 }
 
-int SetCoreClockPLL(volatile STG4000REG pSTGReg, struct pci_dev *pDev)
+int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev)
 {
        u32 F, R, P;
        u16 core_pll = 0, sub;
index 5845dee..e75b3b4 100644 (file)
@@ -16,45 +16,45 @@ struct pci_dev;
 /*
  * Ramdac Setup
  */
-extern int InitialiseRamdac(volatile STG4000REG *pSTGReg, u32 displayDepth,
+extern int InitialiseRamdac(volatile STG4000REG __iomem *pSTGReg, u32 displayDepth,
                            u32 displayWidth, u32 displayHeight,
                            s32 HSyncPolarity, s32 VSyncPolarity,
                            u32 *pixelClock);
 
-extern void DisableRamdacOutput(volatile STG4000REG pSTGReg);
-extern void EnableRamdacOutput(volatile STG4000REG pSTGReg);
+extern void DisableRamdacOutput(volatile STG4000REG __iomem *pSTGReg);
+extern void EnableRamdacOutput(volatile STG4000REG __iomem *pSTGReg);
 
 /*
  * Timing generator setup
  */
-extern void DisableVGA(volatile STG4000REG pSTGReg);
-extern void StopVTG(volatile STG4000REG pSTGReg);
-extern void StartVTG(volatile STG4000REG pSTGReg);
-extern void SetupVTG(volatile STG4000REG pSTGReg,
+extern void DisableVGA(volatile STG4000REG __iomem *pSTGReg);
+extern void StopVTG(volatile STG4000REG __iomem *pSTGReg);
+extern void StartVTG(volatile STG4000REG __iomem *pSTGReg);
+extern void SetupVTG(volatile STG4000REG __iomem *pSTGReg,
                     const struct kyrofb_info * pTiming);
 
 extern u32 ProgramClock(u32 refClock, u32 coreClock, u32 *FOut, u32 *ROut, u32 *POut);
-extern int SetCoreClockPLL(volatile STG4000REG pSTGReg, struct pci_dev *pDev);
+extern int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev);
 
 /*
  * Overlay setup
  */
-extern void ResetOverlayRegisters(volatile STG4000REG pSTGReg);
+extern void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg);
 
-extern int CreateOverlaySurface(volatile STG4000REG pSTGReg,
+extern int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg,
                                u32 ulWidth, u32 ulHeight,
                                int bLinear,
                                u32 ulOverlayOffset,
                                u32 * retStride, u32 * retUVStride);
 
-extern int SetOverlayBlendMode(volatile STG4000REG pSTGReg,
+extern int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg,
                               OVRL_BLEND_MODE mode,
                               u32 ulAlpha, u32 ulColorKey);
 
-extern int SetOverlayViewPort(volatile STG4000REG pSTGReg,
+extern int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg,
                              u32 left, u32 top,
                              u32 right, u32 bottom);
 
-extern void EnableOverlayPlane(volatile STG4000REG pSTGReg);
+extern void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg);
 
 #endif /* _STG4000INTERFACE_H */
index 25b286b..fcdc532 100644 (file)
@@ -75,7 +75,7 @@ typedef struct _OVRL_SRC_DEST {
 static u32 ovlWidth, ovlHeight, ovlStride;
 static int ovlLinear;
 
-void ResetOverlayRegisters(volatile STG4000REG pSTGReg)
+void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg)
 {
        u32 tmp;
 
@@ -136,7 +136,7 @@ void ResetOverlayRegisters(volatile STG4000REG * pSTGReg)
 
 }
 
-int CreateOverlaySurface(volatile STG4000REG pSTGReg,
+int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg,
                         u32 inWidth,
                         u32 inHeight,
                         int bLinear,
@@ -238,7 +238,7 @@ int CreateOverlaySurface(volatile STG4000REG * pSTGReg,
        return 0;
 }
 
-int SetOverlayBlendMode(volatile STG4000REG pSTGReg,
+int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg,
                        OVRL_BLEND_MODE mode,
                        u32 ulAlpha, u32 ulColorKey)
 {
@@ -284,7 +284,7 @@ int SetOverlayBlendMode(volatile STG4000REG * pSTGReg,
        return 0;
 }
 
-void EnableOverlayPlane(volatile STG4000REG pSTGReg)
+void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg)
 {
        u32 tmp;
        /* Enable Overlay */
@@ -313,7 +313,7 @@ static u32 Overlap(u32 ulBits, u32 ulPattern)
 
 }
 
-int SetOverlayViewPort(volatile STG4000REG pSTGReg,
+int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg,
                       u32 left, u32 top,
                       u32 right, u32 bottom)
 {
index 72e019b..76a3527 100644 (file)
@@ -18,9 +18,9 @@
 
 static u32 STG_PIXEL_BUS_WIDTH = 128;  /* 128 bit bus width      */
 static u32 REF_CLOCK = 14318;
-STG4000REG *pSTGReg;
+STG4000REG __iomem *pSTGReg;
 
-int InitialiseRamdac(volatile STG4000REG * pSTGReg,
+int InitialiseRamdac(volatile STG4000REG __iomem * pSTGReg,
                     u32 displayDepth,
                     u32 displayWidth,
                     u32 displayHeight,
@@ -145,7 +145,7 @@ int InitialiseRamdac(volatile STG4000REG * pSTGReg,
 }
 
 /* Ramdac control, turning output to the screen on and off */
-void DisableRamdacOutput(volatile STG4000REG * pSTGReg)
+void DisableRamdacOutput(volatile STG4000REG __iomem * pSTGReg)
 {
        u32 tmp;
 
@@ -154,7 +154,7 @@ void DisableRamdacOutput(volatile STG4000REG * pSTGReg)
        STG_WRITE_REG(DACStreamCtrl, tmp);
 }
 
-void EnableRamdacOutput(volatile STG4000REG * pSTGReg)
+void EnableRamdacOutput(volatile STG4000REG __iomem * pSTGReg)
 {
        u32 tmp;
 
index cff6c5f..244549e 100644 (file)
@@ -21,8 +21,8 @@
 #if defined(__KERNEL__)
 #include <asm/page.h>
 #include <asm/io.h>
-#define STG_WRITE_REG(reg,data) (writel(data,(unsigned long)&pSTGReg->reg))
-#define STG_READ_REG(reg)      (readl((unsigned long)&pSTGReg->reg))
+#define STG_WRITE_REG(reg,data) (writel(data,&pSTGReg->reg))
+#define STG_READ_REG(reg)      (readl(&pSTGReg->reg))
 #else
 #define STG_WRITE_REG(reg,data) (pSTGReg->reg = data)
 #define STG_READ_REG(reg)      (pSTGReg->reg)
index 59c4a18..3690b04 100644 (file)
@@ -14,7 +14,7 @@
 #include "STG4000Reg.h"
 #include "STG4000Interface.h"
 
-void DisableVGA(volatile STG4000REG pSTGReg)
+void DisableVGA(volatile STG4000REG __iomem *pSTGReg)
 {
        u32 tmp;
        volatile u32 count, i;
@@ -35,7 +35,7 @@ void DisableVGA(volatile STG4000REG * pSTGReg)
        STG_WRITE_REG(SoftwareReset, tmp);
 }
 
-void StopVTG(volatile STG4000REG pSTGReg)
+void StopVTG(volatile STG4000REG __iomem *pSTGReg)
 {
        u32 tmp = 0;
 
@@ -45,7 +45,7 @@ void StopVTG(volatile STG4000REG * pSTGReg)
        STG_WRITE_REG(DACSyncCtrl, tmp);
 }
 
-void StartVTG(volatile STG4000REG pSTGReg)
+void StartVTG(volatile STG4000REG __iomem *pSTGReg)
 {
        u32 tmp = 0;
 
@@ -56,7 +56,7 @@ void StartVTG(volatile STG4000REG * pSTGReg)
        STG_WRITE_REG(DACSyncCtrl, tmp);
 }
 
-void SetupVTG(volatile STG4000REG pSTGReg,
+void SetupVTG(volatile STG4000REG __iomem *pSTGReg,
              const struct kyrofb_info * pTiming)
 {
        u32 tmp = 0;
index 99fb72a..7e1e7fb 100644 (file)
@@ -180,11 +180,11 @@ struct leo_ld_gbl {
 
 struct leo_par {
        spinlock_t              lock;
-       struct leo_lx_krn       *lx_krn;
-       struct leo_lc_ss0_usr   *lc_ss0_usr;
-       struct leo_ld_ss0       *ld_ss0;
-       struct leo_ld_ss1       *ld_ss1;
-       struct leo_cursor       *cursor;
+       struct leo_lx_krn       __iomem *lx_krn;
+       struct leo_lc_ss0_usr   __iomem *lc_ss0_usr;
+       struct leo_ld_ss0       __iomem *ld_ss0;
+       struct leo_ld_ss1       __iomem *ld_ss1;
+       struct leo_cursor       __iomem *cursor;
        u32                     extent;
        u32                     clut_data[256];
 
@@ -198,7 +198,7 @@ struct leo_par {
        struct list_head        list;
 };
 
-static void leo_wait(struct leo_lx_krn *lx_krn)
+static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
 {
        int i;
        
@@ -223,7 +223,7 @@ static int leo_setcolreg(unsigned regno,
                         unsigned transp, struct fb_info *info)
 {
        struct leo_par *par = (struct leo_par *) info->par;
-        struct leo_lx_krn *lx_krn = par->lx_krn;
+        struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
        unsigned long flags;
        u32 val;
        int i;
@@ -263,24 +263,24 @@ static int leo_setcolreg(unsigned regno,
 static int leo_blank(int blank, struct fb_info *info)
 {
        struct leo_par *par = (struct leo_par *) info->par;
-       struct leo_lx_krn *lx_krn = par->lx_krn;
+       struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
        unsigned long flags;
        u32 val;
 
        spin_lock_irqsave(&par->lock, flags);
 
        switch (blank) {
-       case 0: /* Unblanking */
+       case FB_BLANK_UNBLANK: /* Unblanking */
                val = sbus_readl(&lx_krn->krn_csr);
                val |= LEO_KRN_CSR_ENABLE;
                sbus_writel(val, &lx_krn->krn_csr);
                par->flags &= ~LEO_FLAG_BLANKED;
                break;
 
-       case 1: /* Normal blanking */
-       case 2: /* VESA blank (vsync off) */
-       case 3: /* VESA blank (hsync off) */
-       case 4: /* Poweroff */
+       case FB_BLANK_NORMAL: /* Normal blanking */
+       case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+       case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+       case FB_BLANK_POWERDOWN: /* Poweroff */
                val = sbus_readl(&lx_krn->krn_csr);
                val &= ~LEO_KRN_CSR_ENABLE;
                sbus_writel(val, &lx_krn->krn_csr);
@@ -403,7 +403,7 @@ leo_init_fix(struct fb_info *info)
 static void leo_wid_put(struct fb_info *info, struct fb_wid_list *wl)
 {
        struct leo_par *par = (struct leo_par *) info->par;
-       struct leo_lx_krn *lx_krn = par->lx_krn;
+       struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
        struct fb_wid_item *wi;
        unsigned long flags;
        u32 val;
@@ -465,7 +465,7 @@ static void leo_init_wids(struct fb_info *info)
 static void leo_switch_from_graph(struct fb_info *info)
 {
        struct leo_par *par = (struct leo_par *) info->par;
-       struct leo_ld *ss = (struct leo_ld *) par->ld_ss0;
+       struct leo_ld __iomem *ss = (struct leo_ld __iomem *) par->ld_ss0;
        unsigned long flags;
        u32 val;
 
@@ -564,33 +564,32 @@ static void leo_init_one(struct sbus_dev *sdev)
        all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
 
 #ifdef CONFIG_SPARC32
-       all->info.screen_base = (char *)
+       all->info.screen_base = (char __iomem *)
                prom_getintdefault(sdev->prom_node, "address", 0);
 #endif
        if (!all->info.screen_base)
-               all->info.screen_base = (char *)
+               all->info.screen_base = 
                        sbus_ioremap(&sdev->resource[0], LEO_OFF_SS0,
                                     0x800000, "leo ram");
 
-       all->par.lc_ss0_usr = (struct leo_lc_ss0_usr *)
+       all->par.lc_ss0_usr =
                sbus_ioremap(&sdev->resource[0], LEO_OFF_LC_SS0_USR,
                             0x1000, "leolc ss0usr");
-       all->par.ld_ss0 = (struct leo_ld_ss0 *)
+       all->par.ld_ss0 =
                sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS0,
                             0x1000, "leold ss0");
-       all->par.ld_ss1 = (struct leo_ld_ss1 *)
+       all->par.ld_ss1 =
                sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS1,
                             0x1000, "leold ss1");
-       all->par.lx_krn = (struct leo_lx_krn *)
+       all->par.lx_krn =
                sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_KRN,
                             0x1000, "leolx krn");
-       all->par.cursor = (struct leo_cursor *)
+       all->par.cursor =
                sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_CURSOR,
                             sizeof(struct leo_cursor), "leolx cursor");
 
        all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
        all->info.fbops = &leo_ops;
-       all->info.currcon = -1;
        all->info.par = &all->par;
 
        leo_init_wids(&all->info);
index fd38e05..8f14c9b 100644 (file)
@@ -411,12 +411,7 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx,
 
        CRITBEGIN
 
-#ifdef __BIG_ENDIAN
-       WaitTillIdle();
-       mga_outl(M_OPMODE, M_OPMODE_8BPP);
-#else
        mga_fifo(3);
-#endif
        if (easy)
                mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
        else
@@ -432,32 +427,24 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx,
        mga_writel(mmio, M_AR3, 0);
        if (easy) {
                mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
-               mga_memcpy_toio(mmio, 0, chardata, xlen);
+               mga_memcpy_toio(mmio, chardata, xlen);
        } else {
                mga_writel(mmio, M_AR5, 0);
                mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
                if ((step & 3) == 0) {
                        /* Great. Source has 32bit aligned lines, so we can feed them
                           directly to the accelerator. */
-                       mga_memcpy_toio(mmio, 0, chardata, charcell);
+                       mga_memcpy_toio(mmio, chardata, charcell);
                } else if (step == 1) {
                        /* Special case for 1..8bit widths */
                        while (height--) {
-#ifdef __LITTLE_ENDIAN
                                mga_writel(mmio, 0, *chardata);
-#else
-                               mga_writel(mmio, 0, (*chardata) << 24);
-#endif
                                chardata++;
                        }
                } else if (step == 2) {
                        /* Special case for 9..15bit widths */
                        while (height--) {
-#ifdef __LITTLE_ENDIAN
                                mga_writel(mmio, 0, *(u_int16_t*)chardata);
-#else
-                               mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16);
-#endif
                                chardata += 2;
                        }
                } else {
@@ -474,9 +461,6 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx,
                }
        }
        WaitTillIdle();
-#ifdef __BIG_ENDIAN
-       mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
-#endif
        CRITEND
 }
 
@@ -486,7 +470,7 @@ static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* imag
 
        DBG_HEAVY(__FUNCTION__);
 
-       if (image->depth == 0) {
+       if (image->depth == 1) {
                u_int32_t fgx, bgx;
 
                fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color];
index 9d92dda..608e40b 100644 (file)
@@ -9,6 +9,7 @@
 struct matroxfb_dh_fb_info {
        struct fb_info          fbcon;
        int                     fbcon_registered;
+       int                     initialized;
 
        struct matrox_fb_info*  primary_dev;
 
index 92a41f7..f5a7763 100644 (file)
@@ -47,20 +47,14 @@ enum {
 };
 
 struct offb_par {
-       volatile unsigned char *cmap_adr;
-       volatile unsigned char *cmap_data;
+       volatile void __iomem *cmap_adr;
+       volatile void __iomem *cmap_data;
        int cmap_type;
        int blanked;
 };
 
 struct offb_par default_par;
 
-#ifdef __powerpc__
-#define mach_eieio()   eieio()
-#else
-#define mach_eieio()   do {} while (0)
-#endif
-
     /*
      *  Interface used by the world
      */
@@ -110,44 +104,36 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 
        switch (par->cmap_type) {
        case cmap_m64:
-               *par->cmap_adr = regno;
-               mach_eieio();
-               *par->cmap_data = red;
-               mach_eieio();
-               *par->cmap_data = green;
-               mach_eieio();
-               *par->cmap_data = blue;
-               mach_eieio();
+               writeb(regno, par->cmap_adr);
+               writeb(red, par->cmap_data);
+               writeb(green, par->cmap_data);
+               writeb(blue, par->cmap_data);
                break;
        case cmap_M3A:
                /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
-               out_le32((unsigned *) (par->cmap_adr + 0x58),
-                        in_le32((unsigned *) (par->cmap_adr +
-                                              0x58)) & ~0x20);
+               out_le32(par->cmap_adr + 0x58,
+                        in_le32(par->cmap_adr + 0x58) & ~0x20);
        case cmap_r128:
                /* Set palette index & data */
                out_8(par->cmap_adr + 0xb0, regno);
-               out_le32((unsigned *) (par->cmap_adr + 0xb4),
+               out_le32(par->cmap_adr + 0xb4,
                         (red << 16 | green << 8 | blue));
                break;
        case cmap_M3B:
                /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
-               out_le32((unsigned *) (par->cmap_adr + 0x58),
-                        in_le32((unsigned *) (par->cmap_adr +
-                                              0x58)) | 0x20);
+               out_le32(par->cmap_adr + 0x58,
+                        in_le32(par->cmap_adr + 0x58) | 0x20);
                /* Set palette index & data */
                out_8(par->cmap_adr + 0xb0, regno);
-               out_le32((unsigned *) (par->cmap_adr + 0xb4),
-                        (red << 16 | green << 8 | blue));
+               out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue));
                break;
        case cmap_radeon:
                /* Set palette index & data (could be smarter) */
                out_8(par->cmap_adr + 0xb0, regno);
-               out_le32((unsigned *) (par->cmap_adr + 0xb4),
-                        (red << 16 | green << 8 | blue));
+               out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue));
                break;
        case cmap_gxt2000:
-               out_le32((unsigned *) par->cmap_adr + regno,
+               out_le32((unsigned __iomem *) par->cmap_adr + regno,
                         (red << 16 | green << 8 | blue));
                break;
        }
@@ -191,47 +177,33 @@ static int offb_blank(int blank, struct fb_info *info)
                for (i = 0; i < 256; i++) {
                        switch (par->cmap_type) {
                        case cmap_m64:
-                               *par->cmap_adr = i;
-                               mach_eieio();
-                               for (j = 0; j < 3; j++) {
-                                       *par->cmap_data = 0;
-                                       mach_eieio();
-                               }
+                               writeb(i, par->cmap_adr);
+                               for (j = 0; j < 3; j++)
+                                       writeb(0, par->cmap_data);
                                break;
                        case cmap_M3A:
                                /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
-                               out_le32((unsigned *) (par->cmap_adr +
-                                                      0x58),
-                                        in_le32((unsigned *) (par->
-                                                              cmap_adr +
-                                                              0x58)) &
-                                        ~0x20);
+                               out_le32(par->cmap_adr + 0x58,
+                                        in_le32(par->cmap_adr + 0x58) & ~0x20);
                        case cmap_r128:
                                /* Set palette index & data */
                                out_8(par->cmap_adr + 0xb0, i);
-                               out_le32((unsigned *) (par->cmap_adr +
-                                                      0xb4), 0);
+                               out_le32(par->cmap_adr + 0xb4, 0);
                                break;
                        case cmap_M3B:
                                /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
-                               out_le32((unsigned *) (par->cmap_adr +
-                                                      0x58),
-                                        in_le32((unsigned *) (par->
-                                                              cmap_adr +
-                                                              0x58)) |
-                                        0x20);
+                               out_le32(par->cmap_adr + 0x58,
+                                        in_le32(par->cmap_adr + 0x58) | 0x20);
                                /* Set palette index & data */
                                out_8(par->cmap_adr + 0xb0, i);
-                               out_le32((unsigned *) (par->cmap_adr +
-                                                      0xb4), 0);
+                               out_le32(par->cmap_adr + 0xb4, 0);
                                break;
                        case cmap_radeon:
                                out_8(par->cmap_adr + 0xb0, i);
-                               out_le32((unsigned *) (par->cmap_adr +
-                                                      0xb4), 0);
+                               out_le32(par->cmap_adr + 0xb4, 0);
                                break;
                        case cmap_gxt2000:
-                               out_le32((unsigned *) par->cmap_adr + i,
+                               out_le32((unsigned __iomem *) par->cmap_adr + i,
                                         0);
                                break;
                        }
index 7fbbef4..7808a01 100644 (file)
@@ -129,7 +129,7 @@ struct p9100_cmd_parameng {
 
 struct p9100_par {
        spinlock_t              lock;
-       struct p9100_regs       *regs;
+       struct p9100_regs       __iomem *regs;
 
        u32                     flags;
 #define P9100_FLAG_BLANKED     0x00000001
@@ -155,7 +155,7 @@ static int p9100_setcolreg(unsigned regno,
                           unsigned transp, struct fb_info *info)
 {
        struct p9100_par *par = (struct p9100_par *) info->par;
-       struct p9100_regs *regs = par->regs;
+       struct p9100_regs __iomem *regs = par->regs;
        unsigned long flags;
 
        if (regno >= 256)
@@ -186,24 +186,24 @@ static int
 p9100_blank(int blank, struct fb_info *info)
 {
        struct p9100_par *par = (struct p9100_par *) info->par;
-       struct p9100_regs *regs = par->regs;
+       struct p9100_regs __iomem *regs = par->regs;
        unsigned long flags;
        u32 val;
 
        spin_lock_irqsave(&par->lock, flags);
 
        switch (blank) {
-       case 0: /* Unblanking */
+       case FB_BLANK_UNBLANK: /* Unblanking */
                val = sbus_readl(&regs->vid_screenpaint_timectl1);
                val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
                sbus_writel(val, &regs->vid_screenpaint_timectl1);
                par->flags &= ~P9100_FLAG_BLANKED;
                break;
 
-       case 1: /* Normal blanking */
-       case 2: /* VESA blank (vsync off) */
-       case 3: /* VESA blank (hsync off) */
-       case 4: /* Poweroff */
+       case FB_BLANK_NORMAL: /* Normal blanking */
+       case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+       case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+       case FB_BLANK_POWERDOWN: /* Poweroff */
                val = sbus_readl(&regs->vid_screenpaint_timectl1);
                val &= ~SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
                sbus_writel(val, &regs->vid_screenpaint_timectl1);
@@ -293,21 +293,18 @@ static void p9100_init_one(struct sbus_dev *sdev)
                                       all->info.var.xres);
        all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
 
-       all->par.regs = (struct p9100_regs *)
-               sbus_ioremap(&sdev->resource[0], 0,
+       all->par.regs = sbus_ioremap(&sdev->resource[0], 0,
                             sizeof(struct p9100_regs), "p9100 regs");
 
        all->info.flags = FBINFO_DEFAULT;
        all->info.fbops = &p9100_ops;
 #ifdef CONFIG_SPARC32
-       all->info.screen_base = (char *)
+       all->info.screen_base = (char __iomem *)
                prom_getintdefault(sdev->prom_node, "address", 0);
 #endif
        if (!all->info.screen_base)
-               all->info.screen_base = (char *)
-                       sbus_ioremap(&sdev->resource[2], 0,
+               all->info.screen_base = sbus_ioremap(&sdev->resource[2], 0,
                                     all->par.fbsize, "p9100 ram");
-       all->info.currcon = -1;
        all->info.par = &all->par;
 
        p9100_blank(0, &all->info);
index 5ad8308..3dd1de1 100644 (file)
@@ -56,14 +56,14 @@ struct fb_info_platinum {
        }                               palette[256];
        u32                             pseudo_palette[17];
        
-       volatile struct cmap_regs       *cmap_regs;
+       volatile struct cmap_regs       __iomem *cmap_regs;
        unsigned long                   cmap_regs_phys;
        
-       volatile struct platinum_regs   *platinum_regs;
+       volatile struct platinum_regs   __iomem *platinum_regs;
        unsigned long                   platinum_regs_phys;
        
-       __u8                            *frame_buffer;
-       volatile __u8                   *base_frame_buffer;
+       __u8                            __iomem *frame_buffer;
+       volatile __u8                   __iomem *base_frame_buffer;
        unsigned long                   frame_buffer_phys;
        
        unsigned long                   total_vram;
@@ -141,7 +141,7 @@ static int platinumfb_set_par (struct fb_info *info)
        
        if (pinfo->vmode == 13 && pinfo->cmode > 0)
                offset = 0x10;
-       info->screen_base = (char *) pinfo->frame_buffer + init->fb_offset + offset;
+       info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
        info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
        info->fix.visual = (pinfo->cmode == CMODE_8) ?
                FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
@@ -184,7 +184,7 @@ static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                              u_int transp, struct fb_info *info)
 {
        struct fb_info_platinum *pinfo = info->par;
-       volatile struct cmap_regs *cmap_regs = pinfo->cmap_regs;
+       volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
 
        if (regno > 255)
                return 1;
@@ -232,7 +232,7 @@ static inline int platinum_vram_reqd(int video_mode, int color_mode)
 
 static void set_platinum_clock(struct fb_info_platinum *pinfo)
 {
-       volatile struct cmap_regs *cmap_regs = pinfo->cmap_regs;
+       volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
        struct platinum_regvals *init;
 
        init = platinum_reg_init[pinfo->vmode-1];
@@ -259,8 +259,8 @@ static void set_platinum_clock(struct fb_info_platinum *pinfo)
 /* Some things in here probably don't need to be done each time. */
 static void platinum_set_hardware(struct fb_info_platinum *pinfo)
 {
-       volatile struct platinum_regs   *platinum_regs = pinfo->platinum_regs;
-       volatile struct cmap_regs       *cmap_regs = pinfo->cmap_regs;
+       volatile struct platinum_regs   __iomem *platinum_regs = pinfo->platinum_regs;
+       volatile struct cmap_regs       __iomem *cmap_regs = pinfo->cmap_regs;
        struct platinum_regvals         *init;
        int                             i;
        int                             vmode, cmode;
@@ -312,7 +312,7 @@ static void __devinit platinum_init_info(struct fb_info *info, struct fb_info_pl
        info->fbops = &platinumfb_ops;
        info->pseudo_palette = pinfo->pseudo_palette;
         info->flags = FBINFO_DEFAULT;
-       info->screen_base = (char *) pinfo->frame_buffer + 0x20;
+       info->screen_base = pinfo->frame_buffer + 0x20;
 
        fb_alloc_cmap(&info->cmap, 256, 0);
 
@@ -404,7 +404,7 @@ try_again:
  */
 static int read_platinum_sense(struct fb_info_platinum *info)
 {
-       volatile struct platinum_regs *platinum_regs = info->platinum_regs;
+       volatile struct platinum_regs __iomem *platinum_regs = info->platinum_regs;
        int sense;
 
        out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */
@@ -637,10 +637,10 @@ static int __devexit platinumfb_remove(struct of_device* odev)
                size = dp->addrs[i].size;
                release_mem_region(addr, size);
        }
-       iounmap((void *)pinfo->frame_buffer);
-       iounmap((void *)pinfo->platinum_regs);
+       iounmap(pinfo->frame_buffer);
+       iounmap(pinfo->platinum_regs);
        release_mem_region(pinfo->cmap_regs_phys, 0x1000);
-       iounmap((void *)pinfo->cmap_regs);
+       iounmap(pinfo->cmap_regs);
 
        framebuffer_release(info);
 
index a6ecf96..f4b2070 100644 (file)
@@ -939,6 +939,7 @@ static int __devinit pvr2fb_pci_probe(struct pci_dev *pdev,
 
        pvr2_fix.mmio_start     = pci_resource_start(pdev, 1);
        pvr2_fix.mmio_len       = pci_resource_len(pdev, 1);
+       fbinfo->device = &pdev->dev;
 
        return pvr2fb_common_init();
 }
index 3e2bb2d..a8389c6 100644 (file)
@@ -371,9 +371,10 @@ static int pxafb_blank(int blank, struct fb_info *info)
        DPRINTK("pxafb_blank: blank=%d\n", blank);
 
        switch (blank) {
-       case VESA_POWERDOWN:
-       case VESA_VSYNC_SUSPEND:
-       case VESA_HSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_NORMAL:
                if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
                    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
                        for (i = 0; i < fbi->palette_size; i++)
@@ -383,7 +384,7 @@ static int pxafb_blank(int blank, struct fb_info *info)
                //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
                break;
 
-       case VESA_NO_BLANKING:
+       case FB_BLANK_UNBLANK:
                //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
                if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
                    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
@@ -652,6 +653,7 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
 
 static void pxafb_setup_gpio(struct pxafb_info *fbi)
 {
+       int gpio, ldd_bits;
         unsigned int lccr0 = fbi->lccr0;
 
        /*
@@ -662,49 +664,31 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi)
        if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
            (lccr0 & LCCR0_SDS) == LCCR0_Sngl &&
            (lccr0 & LCCR0_DPD) == LCCR0_4PixMono)
-       {
-               // bits 58-61
-               GPDR1 |= (0xf << 26);
-               GAFR1_U = (GAFR1_U & ~(0xff << 20)) | (0xaa << 20);
-
-               // bits 74-77
-               GPDR2 |= (0xf << 10);
-               GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
-       }
+               ldd_bits = 4;
 
        /* 8 bit interface */
         else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
                  ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
                  ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
                  (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
-       {
-               // bits 58-65
-               GPDR1 |= (0x3f << 26);
-               GPDR2 |= (0x3);
-
-               GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
-               GAFR2_L = (GAFR2_L & ~0xf) | (0xa);
-
-               // bits 74-77
-               GPDR2 |= (0xf << 10);
-               GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
-       }
+               ldd_bits = 8;
 
        /* 16 bit interface */
        else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
                 ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
-       {
-               // bits 58-77
-               GPDR1 |= (0x3f << 26);
-               GPDR2 |= 0x00003fff;
-
-               GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
-               GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
-       }
+               ldd_bits = 16;
 
        else {
                printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+               return;
         }
+
+       for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
+               pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
+       pxa_gpio_mode(GPIO74_LCD_FCLK_MD);
+       pxa_gpio_mode(GPIO75_LCD_LCLK_MD);
+       pxa_gpio_mode(GPIO76_LCD_PCLK_MD);
+       pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD);
 }
 
 static void pxafb_enable_controller(struct pxafb_info *fbi)
@@ -1043,7 +1027,6 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
        fbi->fb.fbops           = &pxafb_ops;
        fbi->fb.flags           = FBINFO_DEFAULT;
        fbi->fb.node            = -1;
-       fbi->fb.currcon         = -1;
 
        addr = fbi;
        addr = addr + sizeof(struct pxafb_info);
index 983b728..be630a0 100644 (file)
@@ -56,32 +56,33 @@ static inline unsigned char MISCin(struct riva_par *par)
 static Bool 
 riva_is_connected(struct riva_par *par, Bool second)
 {
-       volatile U032 *PRAMDAC = par->riva.PRAMDAC0;
+       volatile U032 __iomem *PRAMDAC = par->riva.PRAMDAC0;
        U032 reg52C, reg608;
        Bool present;
 
        if(second) PRAMDAC += 0x800;
 
-       reg52C = PRAMDAC[0x052C/4];
-       reg608 = PRAMDAC[0x0608/4];
+       reg52C = NV_RD32(PRAMDAC, 0x052C);
+       reg608 = NV_RD32(PRAMDAC, 0x0608);
 
-       PRAMDAC[0x0608/4] = reg608 & ~0x00010000;
+       NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000);
 
-       PRAMDAC[0x052C/4] = reg52C & 0x0000FEEE;
+       NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE);
        mdelay(1); 
-       PRAMDAC[0x052C/4] |= 1;
+       NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1);
 
-       par->riva.PRAMDAC0[0x0610/4] = 0x94050140;
-       par->riva.PRAMDAC0[0x0608/4] |= 0x00001000;
+       NV_WR32(par->riva.PRAMDAC0, 0x0610, 0x94050140);
+       NV_WR32(par->riva.PRAMDAC0, 0x0608, 0x00001000);
 
        mdelay(1);
 
-       present = (PRAMDAC[0x0608/4] & (1 << 28)) ? TRUE : FALSE;
+       present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? TRUE : FALSE;
 
-       par->riva.PRAMDAC0[0x0608/4] &= 0x0000EFFF;
+       NV_WR32(par->riva.PRAMDAC0, 0x0608,
+               NV_RD32(par->riva.PRAMDAC0, 0x0608) & 0x0000EFFF);
 
-       PRAMDAC[0x052C/4] = reg52C;
-       PRAMDAC[0x0608/4] = reg608;
+       NV_WR32(PRAMDAC, 0x052C, reg52C);
+       NV_WR32(PRAMDAC, 0x0608, reg608);
 
        return present;
 }
@@ -104,12 +105,33 @@ static void
 riva_is_second(struct riva_par *par)
 {
        if (par->FlatPanel == 1) {
-               switch(par->Chipset) {
-               case NV_CHIP_GEFORCE4_440_GO:
-               case NV_CHIP_GEFORCE4_440_GO_M64:
-               case NV_CHIP_GEFORCE4_420_GO:
-               case NV_CHIP_GEFORCE4_420_GO_M32:
-               case NV_CHIP_QUADRO4_500_GOGL:
+               switch(par->Chipset & 0xffff) {
+               case 0x0174:
+               case 0x0175:
+               case 0x0176:
+               case 0x0177:
+               case 0x0179:
+               case 0x017C:
+               case 0x017D:
+               case 0x0186:
+               case 0x0187:
+               /* this might not be a good default for the chips below */
+               case 0x0286:
+               case 0x028C:
+               case 0x0316:
+               case 0x0317:
+               case 0x031A:
+               case 0x031B:
+               case 0x031C:
+               case 0x031D:
+               case 0x031E:
+               case 0x031F:
+               case 0x0324:
+               case 0x0325:
+               case 0x0328:
+               case 0x0329:
+               case 0x032C:
+               case 0x032D:
                        par->SecondCRTC = TRUE;
                        break;
                default:
@@ -118,13 +140,14 @@ riva_is_second(struct riva_par *par)
                }
        } else {
                if(riva_is_connected(par, 0)) {
-                       if(par->riva.PRAMDAC0[0x0000052C/4] & 0x100)
+
+                       if (NV_RD32(par->riva.PRAMDAC0, 0x0000052C) & 0x100)
                                par->SecondCRTC = TRUE;
                        else
                                par->SecondCRTC = FALSE;
                } else 
                if (riva_is_connected(par, 1)) {
-                       if(par->riva.PRAMDAC0[0x0000252C/4] & 0x100)
+                       if(NV_RD32(par->riva.PRAMDAC0, 0x0000252C) & 0x100)
                                par->SecondCRTC = TRUE;
                        else
                                par->SecondCRTC = FALSE;
@@ -144,13 +167,13 @@ unsigned long riva_get_memlen(struct riva_par *par)
 
        switch (chip->Architecture) {
        case NV_ARCH_03:
-               if (chip->PFB[0x00000000/4] & 0x00000020) {
-                       if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
-                           && ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02)) {
+               if (NV_RD32(chip->PFB, 0x00000000) & 0x00000020) {
+                       if (((NV_RD32(chip->PMC, 0x00000000) & 0xF0) == 0x20)
+                           && ((NV_RD32(chip->PMC, 0x00000000)&0x0F)>=0x02)) {
                                /*
                                 * SDRAM 128 ZX.
                                 */
-                               switch (chip->PFB[0x00000000/4] & 0x03) {
+                               switch (NV_RD32(chip->PFB,0x00000000) & 0x03) {
                                case 2:
                                        memlen = 1024 * 4;
                                        break;
@@ -168,7 +191,7 @@ unsigned long riva_get_memlen(struct riva_par *par)
                        /*
                         * SGRAM 128.
                         */
-                       switch (chip->PFB[0x00000000/4] & 0x00000003) {
+                       switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003) {
                        case 0:
                                memlen = 1024 * 8;
                                break;
@@ -182,11 +205,11 @@ unsigned long riva_get_memlen(struct riva_par *par)
                }        
                break;
        case NV_ARCH_04:
-               if (chip->PFB[0x00000000/4] & 0x00000100) {
-                       memlen = ((chip->PFB[0x00000000/4] >> 12) & 0x0F) * 
+               if (NV_RD32(chip->PFB, 0x00000000) & 0x00000100) {
+                       memlen = ((NV_RD32(chip->PFB, 0x00000000)>>12)&0x0F) *
                                1024 * 2 + 1024 * 2;
                } else {
-                       switch (chip->PFB[0x00000000/4] & 0x00000003) {
+                       switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003) {
                        case 0:
                                memlen = 1024 * 32;
                                break;
@@ -216,7 +239,8 @@ unsigned long riva_get_memlen(struct riva_par *par)
                        pci_read_config_dword(dev, 0x84, &amt);
                        memlen = (((amt >> 4) & 127) + 1) * 1024;
                } else {
-                       switch ((chip->PFB[0x0000020C/4] >> 20) & 0x000000FF){
+                       switch ((NV_RD32(chip->PFB, 0x0000020C) >> 20) &
+                               0x000000FF){
                        case 0x02:
                                memlen = 1024 * 2;
                                break;
@@ -255,9 +279,9 @@ unsigned long riva_get_maxdclk(struct riva_par *par)
 
        switch (chip->Architecture) {
        case NV_ARCH_03:
-               if (chip->PFB[0x00000000/4] & 0x00000020) {
-                       if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
-                           && ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02)) {   
+               if (NV_RD32(chip->PFB, 0x00000000) & 0x00000020) {
+                       if (((NV_RD32(chip->PMC, 0x00000000) & 0xF0) == 0x20)
+                           && ((NV_RD32(chip->PMC,0x00000000)&0x0F) >= 0x02)) {
                                /*
                                 * SDRAM 128 ZX.
                                 */
@@ -276,7 +300,7 @@ unsigned long riva_get_maxdclk(struct riva_par *par)
        case NV_ARCH_10:
        case NV_ARCH_20:
        case NV_ARCH_30:
-               switch ((chip->PFB[0x00000000/4] >> 3) & 0x00000003) {
+               switch ((NV_RD32(chip->PFB, 0x00000000) >> 3) & 0x00000003) {
                case 3:
                        dclk = 800000;
                        break;
@@ -293,28 +317,56 @@ void
 riva_common_setup(struct riva_par *par)
 {
        par->riva.EnableIRQ = 0;
-       par->riva.PRAMDAC0 = (unsigned *)(par->ctrl_base + 0x00680000);
-       par->riva.PFB = (unsigned *)(par->ctrl_base + 0x00100000);
-       par->riva.PFIFO = (unsigned *)(par->ctrl_base + 0x00002000);
-       par->riva.PGRAPH = (unsigned *)(par->ctrl_base + 0x00400000);
-       par->riva.PEXTDEV = (unsigned *)(par->ctrl_base + 0x00101000);
-       par->riva.PTIMER = (unsigned *)(par->ctrl_base + 0x00009000);
-       par->riva.PMC = (unsigned *)(par->ctrl_base + 0x00000000);
-       par->riva.FIFO = (unsigned *)(par->ctrl_base + 0x00800000);
-       par->riva.PCIO0 = (U008 *)(par->ctrl_base + 0x00601000);
-       par->riva.PDIO0 = (U008 *)(par->ctrl_base + 0x00681000);
-       par->riva.PVIO = (U008 *)(par->ctrl_base + 0x000C0000);
+       par->riva.PRAMDAC0 =
+               (volatile U032 __iomem *)(par->ctrl_base + 0x00680000);
+       par->riva.PFB =
+               (volatile U032 __iomem *)(par->ctrl_base + 0x00100000);
+       par->riva.PFIFO =
+               (volatile U032 __iomem *)(par->ctrl_base + 0x00002000);
+       par->riva.PGRAPH =
+               (volatile U032 __iomem *)(par->ctrl_base + 0x00400000);
+       par->riva.PEXTDEV =
+               (volatile U032 __iomem *)(par->ctrl_base + 0x00101000);
+       par->riva.PTIMER =
+               (volatile U032 __iomem *)(par->ctrl_base + 0x00009000);
+       par->riva.PMC =
+               (volatile U032 __iomem *)(par->ctrl_base + 0x00000000);
+       par->riva.FIFO =
+               (volatile U032 __iomem *)(par->ctrl_base + 0x00800000);
+       par->riva.PCIO0 = par->ctrl_base + 0x00601000;
+       par->riva.PDIO0 = par->ctrl_base + 0x00681000;
+       par->riva.PVIO = par->ctrl_base + 0x000C0000;
 
        par->riva.IO = (MISCin(par) & 0x01) ? 0x3D0 : 0x3B0;
        
        if (par->FlatPanel == -1) {
-               switch (par->Chipset) {
-               case NV_CHIP_GEFORCE4_440_GO:
-               case NV_CHIP_GEFORCE4_440_GO_M64:
-               case NV_CHIP_GEFORCE4_420_GO:
-               case NV_CHIP_GEFORCE4_420_GO_M32:
-               case NV_CHIP_QUADRO4_500_GOGL:
-               case NV_CHIP_GEFORCE2_GO:
+               switch (par->Chipset & 0xffff) {
+               case 0x0112:   /* known laptop chips */
+               case 0x0174:
+               case 0x0175:
+               case 0x0176:
+               case 0x0177:
+               case 0x0179:
+               case 0x017C:
+               case 0x017D:
+               case 0x0186:
+               case 0x0187:
+               case 0x0286:
+               case 0x028C:
+               case 0x0316:
+               case 0x0317:
+               case 0x031A:
+               case 0x031B:
+               case 0x031C:
+               case 0x031D:
+               case 0x031E:
+               case 0x031F:
+               case 0x0324:
+               case 0x0325:
+               case 0x0328:
+               case 0x0329:
+               case 0x032C:
+               case 0x032D:
                        printk(KERN_INFO PFX 
                                "On a laptop.  Assuming Digital Flat Panel\n");
                        par->FlatPanel = 1;
@@ -339,6 +391,11 @@ riva_common_setup(struct riva_par *par)
        case 0x01F0:
        case 0x0250:
        case 0x0280:
+       case 0x0300:
+       case 0x0310:
+       case 0x0320:
+       case 0x0330:
+       case 0x0340:
                riva_is_second(par);
                break;
        default:
@@ -362,5 +419,7 @@ riva_common_setup(struct riva_par *par)
                par->FlatPanel = 0;
        }
        par->riva.flatPanel = (par->FlatPanel > 0) ? TRUE : FALSE;
+
+       RivaGetConfig(&par->riva, par->Chipset);
 }
 
index 707022a..a1e71a6 100644 (file)
@@ -73,20 +73,17 @@ typedef unsigned int   U032;
 /*
  * HW access macros.
  */
-#if defined(__powerpc__)
 #include <asm/io.h>
-#define NV_WR08(p,i,d) out_8(p+i, d)
-#define NV_RD08(p,i)   in_8(p+i)
-#else
-#define NV_WR08(p,i,d)  (((U008 *)(p))[i]=(d))
-#define NV_RD08(p,i)    (((U008 *)(p))[i])
-#endif
-#define NV_WR16(p,i,d)  (((U016 *)(p))[(i)/2]=(d))
-#define NV_RD16(p,i)    (((U016 *)(p))[(i)/2])
-#define NV_WR32(p,i,d)  (((U032 *)(p))[(i)/4]=(d))
-#define NV_RD32(p,i)    (((U032 *)(p))[(i)/4])
-#define VGA_WR08(p,i,d) NV_WR08(p,i,d)
-#define VGA_RD08(p,i)   NV_RD08(p,i)
+
+#define NV_WR08(p,i,d)  (__raw_writeb((d), (void __iomem *)(p) + (i)))
+#define NV_RD08(p,i)    (__raw_readb((void __iomem *)(p) + (i)))
+#define NV_WR16(p,i,d)  (__raw_writew((d), (void __iomem *)(p) + (i)))
+#define NV_RD16(p,i)    (__raw_readw((void __iomem *)(p) + (i)))
+#define NV_WR32(p,i,d)  (__raw_writel((d), (void __iomem *)(p) + (i)))
+#define NV_RD32(p,i)    (__raw_readl((void __iomem *)(p) + (i)))
+
+#define VGA_WR08(p,i,d) (writeb((d), (void __iomem *)(p) + (i)))
+#define VGA_RD08(p,i)   (readb((void __iomem *)(p) + (i)))
 
 /*
  * Define different architectures.
@@ -444,24 +441,24 @@ typedef struct _riva_hw_inst
     /*
      * Non-FIFO registers.
      */
-    volatile U032 *PCRTC0;
-    volatile U032 *PCRTC;
-    volatile U032 *PRAMDAC0;
-    volatile U032 *PFB;
-    volatile U032 *PFIFO;
-    volatile U032 *PGRAPH;
-    volatile U032 *PEXTDEV;
-    volatile U032 *PTIMER;
-    volatile U032 *PMC;
-    volatile U032 *PRAMIN;
-    volatile U032 *FIFO;
-    volatile U032 *CURSOR;
-    volatile U008 *PCIO0;
-    volatile U008 *PCIO;
-    volatile U008 *PVIO;
-    volatile U008 *PDIO0;
-    volatile U008 *PDIO;
-    volatile U032 *PRAMDAC;
+    volatile U032 __iomem *PCRTC0;
+    volatile U032 __iomem *PCRTC;
+    volatile U032 __iomem *PRAMDAC0;
+    volatile U032 __iomem *PFB;
+    volatile U032 __iomem *PFIFO;
+    volatile U032 __iomem *PGRAPH;
+    volatile U032 __iomem *PEXTDEV;
+    volatile U032 __iomem *PTIMER;
+    volatile U032 __iomem *PMC;
+    volatile U032 __iomem *PRAMIN;
+    volatile U032 __iomem *FIFO;
+    volatile U032 __iomem *CURSOR;
+    volatile U008 __iomem *PCIO0;
+    volatile U008 __iomem *PCIO;
+    volatile U008 __iomem *PVIO;
+    volatile U008 __iomem *PDIO0;
+    volatile U008 __iomem *PDIO;
+    volatile U032 __iomem *PRAMDAC;
     /*
      * Common chip functions.
      */
@@ -481,15 +478,15 @@ typedef struct _riva_hw_inst
     /*
      * FIFO registers.
      */
-    RivaRop                 *Rop;
-    RivaPattern             *Patt;
-    RivaClip                *Clip;
-    RivaPixmap              *Pixmap;
-    RivaScreenBlt           *Blt;
-    RivaBitmap              *Bitmap;
-    RivaLine                *Line;
-    RivaTexturedTriangle03  *Tri03;
-    RivaTexturedTriangle05  *Tri05;
+    RivaRop                 __iomem *Rop;
+    RivaPattern             __iomem *Patt;
+    RivaClip                __iomem *Clip;
+    RivaPixmap              __iomem *Pixmap;
+    RivaScreenBlt           __iomem *Blt;
+    RivaBitmap              __iomem *Bitmap;
+    RivaLine                __iomem *Line;
+    RivaTexturedTriangle03  __iomem *Tri03;
+    RivaTexturedTriangle05  __iomem *Tri05;
 } RIVA_HW_INST;
 /*
  * Extended mode state information.
@@ -541,8 +538,10 @@ int RivaGetConfig(RIVA_HW_INST *, unsigned int);
 
 #define RIVA_FIFO_FREE(hwinst,hwptr,cnt)                            \
 {                                                                   \
-    while ((hwinst).FifoFreeCount < (cnt))                          \
-        (hwinst).FifoFreeCount = (hwinst).hwptr->FifoFree >> 2;     \
+    while ((hwinst).FifoFreeCount < (cnt)) {                        \
+       mb();mb();                                                  \
+        (hwinst).FifoFreeCount = NV_RD32(&(hwinst).hwptr->FifoFree, 0) >> 2;     \
+    }                                                              \
     (hwinst).FifoFreeCount -= (cnt);                                \
 }
 #endif /* __RIVA_HW_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");
index 3820d7e..90a61ad 100644 (file)
@@ -52,7 +52,7 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map,
        off = vma->vm_pgoff << PAGE_SHIFT;
 
        /* To stop the swapper from even considering these pages */
-       vma->vm_flags |= (VM_SHM | VM_IO | VM_LOCKED);
+       vma->vm_flags |= (VM_IO | VM_RESERVED);
        
        /* Each page, see which map applies */
        for (page = 0; page < size; ){
index 4fc5482..8413907 100644 (file)
@@ -719,8 +719,8 @@ static int sgivwfb_mmap(struct fb_info *info, struct file *file,
        pgprot_val(vma->vm_page_prot) =
            pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
        vma->vm_flags |= VM_IO;
-       if (remap_page_range
-           (vma, vma->vm_start, offset, size, vma->vm_page_prot))
+       if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
+                                               size, vma->vm_page_prot))
                return -EAGAIN;
        vma->vm_file = file;
        printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
index 4b7e498..8b76a91 100644 (file)
@@ -112,6 +112,7 @@ struct stifb_info {
        ngle_rom_t ngle_rom;
        struct sti_struct *sti;
        int deviceSpecificConfig;
+       u32 pseudo_palette[16];
 };
 
 static int __initdata bpp = 8; /* parameter from modprobe */
@@ -1030,6 +1031,14 @@ stifb_setcolreg(u_int regno, u_int red, u_int green,
                                /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
                START_COLORMAPLOAD(fb, lutBltCtl.all);
                SETUP_FB(fb);
+
+               /* info->var.bits_per_pixel == 32 */
+               if (regno < 16) 
+                 ((u32 *)(info->pseudo_palette))[regno] =
+                       (red   << info->var.red.offset)   |
+                       (green << info->var.green.offset) |
+                       (blue  << info->var.blue.offset);
+
        } else {
                /* cleanup colormap hardware */
                FINISH_IMAGE_COLORMAP_ACCESS(fb);
@@ -1326,7 +1335,7 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
        info->fbops = &stifb_ops;
        info->screen_base = (void*) REGION_BASE(fb,1);
        info->flags = FBINFO_DEFAULT;
-       info->currcon = -1;
+       info->pseudo_palette = &fb->pseudo_palette;
 
        /* This has to been done !!! */
        fb_alloc_cmap(&info->cmap, 256, 0);
@@ -1383,6 +1392,7 @@ int __init
 stifb_init(void)
 {
        struct sti_struct *sti;
+       struct sti_struct *def_sti;
        int i;
        
 #ifndef MODULE
@@ -1397,9 +1407,19 @@ stifb_init(void)
                return -ENXIO;
        }
        
+       def_sti = sti_get_rom(0);
+       if (def_sti) {
+               for (i = 1; i < MAX_STI_ROMS; i++) {
+                       sti = sti_get_rom(i);
+                       if (sti == def_sti && bpp > 0)
+                               stifb_force_bpp[i] = bpp;
+               }
+               stifb_init_fb(def_sti, stifb_force_bpp[i]);
+       }
+
        for (i = 1; i < MAX_STI_ROMS; i++) {
                sti = sti_get_rom(i);
-               if (!sti)
+               if (!sti || sti==def_sti)
                        break;
                if (bpp > 0)
                        stifb_force_bpp[i] = bpp;
index e3e43ca..e2fa9e1 100644 (file)
@@ -106,10 +106,10 @@ struct bt_regs {
 
 struct tcx_par {
        spinlock_t              lock;
-       struct bt_regs          *bt;
-       struct tcx_thc          *thc;
-       struct tcx_tec          *tec;
-       volatile u32            *cplane;
+       struct bt_regs          __iomem *bt;
+       struct tcx_thc          __iomem *thc;
+       struct tcx_tec          __iomem *tec;
+       volatile u32            __iomem *cplane;
 
        u32                     flags;
 #define TCX_FLAG_BLANKED       0x00000001
@@ -127,7 +127,7 @@ struct tcx_par {
 /* Reset control plane so that WID is 8-bit plane. */
 static void __tcx_set_control_plane (struct tcx_par *par)
 {
-       volatile u32 *p, *pend;
+       volatile u32 __iomem *p, *pend;
         
        if (par->lowdepth)
                return;
@@ -167,7 +167,7 @@ static int tcx_setcolreg(unsigned regno,
                         unsigned transp, struct fb_info *info)
 {
        struct tcx_par *par = (struct tcx_par *) info->par;
-       struct bt_regs *bt = par->bt;
+       struct bt_regs __iomem *bt = par->bt;
        unsigned long flags;
 
        if (regno >= 256)
@@ -198,7 +198,7 @@ static int
 tcx_blank(int blank, struct fb_info *info)
 {
        struct tcx_par *par = (struct tcx_par *) info->par;
-       struct tcx_thc *thc = par->thc;
+       struct tcx_thc __iomem *thc = par->thc;
        unsigned long flags;
        u32 val;
 
@@ -207,26 +207,26 @@ tcx_blank(int blank, struct fb_info *info)
        val = sbus_readl(&thc->thc_misc);
 
        switch (blank) {
-       case 0: /* Unblanking */
+       case FB_BLANK_UNBLANK: /* Unblanking */
                val &= ~(TCX_THC_MISC_VSYNC_DIS |
                         TCX_THC_MISC_HSYNC_DIS);
                val |= TCX_THC_MISC_VIDEO;
                par->flags &= ~TCX_FLAG_BLANKED;
                break;
 
-       case 1: /* Normal blanking */
+       case FB_BLANK_NORMAL: /* Normal blanking */
                val &= ~TCX_THC_MISC_VIDEO;
                par->flags |= TCX_FLAG_BLANKED;
                break;
 
-       case 2: /* VESA blank (vsync off) */
+       case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
                val |= TCX_THC_MISC_VSYNC_DIS;
                break;
-       case 3: /* VESA blank (hsync off) */
+       case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
                val |= TCX_THC_MISC_HSYNC_DIS;
                break;
 
-       case 4: /* Poweroff */
+       case FB_BLANK_POWERDOWN: /* Poweroff */
                break;
        };
 
@@ -371,19 +371,15 @@ static void tcx_init_one(struct sbus_dev *sdev)
                                       all->info.var.xres);
        all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
 
-       all->par.tec = (struct tcx_tec *)
-               sbus_ioremap(&sdev->resource[7], 0,
+       all->par.tec = sbus_ioremap(&sdev->resource[7], 0,
                             sizeof(struct tcx_tec), "tcx tec");
-       all->par.thc = (struct tcx_thc *)
-               sbus_ioremap(&sdev->resource[9], 0,
+       all->par.thc = sbus_ioremap(&sdev->resource[9], 0,
                             sizeof(struct tcx_thc), "tcx thc");
-       all->par.bt = (struct bt_regs *)
-               sbus_ioremap(&sdev->resource[8], 0,
+       all->par.bt = sbus_ioremap(&sdev->resource[8], 0,
                             sizeof(struct bt_regs), "tcx dac");
        memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map));
        if (!all->par.lowdepth) {
-               all->par.cplane = (volatile u32 *)
-                       sbus_ioremap(&sdev->resource[4], 0,
+               all->par.cplane = sbus_ioremap(&sdev->resource[4], 0,
                                     all->par.fbsize * sizeof(u32), "tcx cplane");
        } else {
                all->par.mmap_map[1].size = SBUS_MMAP_EMPTY;
@@ -415,14 +411,12 @@ static void tcx_init_one(struct sbus_dev *sdev)
        all->info.flags = FBINFO_DEFAULT;
        all->info.fbops = &tcx_ops;
 #ifdef CONFIG_SPARC32
-       all->info.screen_base = (char *)
+       all->info.screen_base = (char __iomem *)
                prom_getintdefault(sdev->prom_node, "address", 0);
 #endif
        if (!all->info.screen_base)
-               all->info.screen_base = (char *)
-                       sbus_ioremap(&sdev->resource[0], 0,
+               all->info.screen_base = sbus_ioremap(&sdev->resource[0], 0,
                                     all->par.fbsize, "tcx ram");
-       all->info.currcon = -1;
        all->info.par = &all->par;
 
        /* Initialize brooktree DAC. */
index cdb1b14..31a2bbc 100644 (file)
@@ -89,13 +89,13 @@ struct fb_par_valkyrie {
 struct fb_info_valkyrie {
        struct fb_info          info;
        struct fb_par_valkyrie  par;
-       struct cmap_regs        *cmap_regs;
+       struct cmap_regs        __iomem *cmap_regs;
        unsigned long           cmap_regs_phys;
        
-       struct valkyrie_regs    *valkyrie_regs;
+       struct valkyrie_regs    __iomem *valkyrie_regs;
        unsigned long           valkyrie_regs_phys;
        
-       __u8                    *frame_buffer;
+       __u8                    __iomem *frame_buffer;
        unsigned long           frame_buffer_phys;
        
        int                     sense;
@@ -142,7 +142,7 @@ static struct fb_ops valkyriefb_ops = {
 static int valkyriefb_set_par(struct fb_info *info)
 {
        struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info;
-       volatile struct valkyrie_regs *valkyrie_regs = p->valkyrie_regs;
+       volatile struct valkyrie_regs __iomem *valkyrie_regs = p->valkyrie_regs;
        struct fb_par_valkyrie *par = info->par;
        struct valkyrie_regvals *init;
        int err;
@@ -207,13 +207,13 @@ static int valkyriefb_blank(int blank_mode, struct fb_info *info)
                return 1;
 
        switch (blank_mode) {
-       case 0:                 /* unblank */
+       case FB_BLANK_UNBLANK:                  /* unblank */
                out_8(&p->valkyrie_regs->mode.r, init->mode);
                break;
-       case 1:
+       case FB_BLANK_NORMAL:
                return 1;       /* get caller to set CLUT to all black */
-       case VESA_VSYNC_SUSPEND+1:
-       case VESA_HSYNC_SUSPEND+1:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
                /*
                 * [kps] Value extracted from MacOS. I don't know
                 * whether this bit disables hsync or vsync, or
@@ -221,7 +221,7 @@ static int valkyriefb_blank(int blank_mode, struct fb_info *info)
                 */
                out_8(&p->valkyrie_regs->mode.r, init->mode | 0x40);
                break;
-       case VESA_POWERDOWN+1:
+       case FB_BLANK_POWERDOWN:
                out_8(&p->valkyrie_regs->mode.r, 0x66);
                break;
        }
@@ -232,7 +232,7 @@ static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                             u_int transp, struct fb_info *info)
 {
        struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info;
-       volatile struct cmap_regs *cmap_regs = p->cmap_regs;
+       volatile struct cmap_regs __iomem *cmap_regs = p->cmap_regs;
        struct fb_par_valkyrie *par = info->par;
 
        if (regno > 255)
@@ -341,21 +341,23 @@ int __init valkyriefb_init(void)
        cmap_regs_phys = 0x50f24000;
        flags = IOMAP_NOCACHE_SER; /* IOMAP_WRITETHROUGH?? */
 #else /* ppc (!CONFIG_MAC) */
-       struct device_node *dp;
+       {
+               struct device_node *dp;
 
-       dp = find_devices("valkyrie");
-       if (dp == 0)
-               return 0;
+               dp = find_devices("valkyrie");
+               if (dp == 0)
+                       return 0;
 
-       if (dp->n_addrs != 1) {
-               printk(KERN_ERR "expecting 1 address for valkyrie (got %d)\n",
-                      dp->n_addrs);
-               return 0;
-       }
+               if (dp->n_addrs != 1) {
+                       printk(KERN_ERR "expecting 1 address for valkyrie (got %d)\n",
+                              dp->n_addrs);
+                       return 0;
+               }
 
-       frame_buffer_phys = dp->addrs[0].address;
-       cmap_regs_phys = dp->addrs[0].address+0x304000;
-       flags = _PAGE_WRITETHRU;
+               frame_buffer_phys = dp->addrs[0].address;
+               cmap_regs_phys = dp->addrs[0].address+0x304000;
+               flags = _PAGE_WRITETHRU;
+       }
 #endif /* ppc (!CONFIG_MAC) */
 
        p = kmalloc(sizeof(*p), GFP_ATOMIC);
@@ -544,7 +546,7 @@ static void valkyrie_par_to_fix(struct fb_par_valkyrie *par,
 static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
 {
        info->fbops = &valkyriefb_ops;
-       info->screen_base = (char *) p->frame_buffer + 0x1000;
+       info->screen_base = p->frame_buffer + 0x1000;
        info->flags = FBINFO_DEFAULT;
        info->pseudo_palette = p->pseudo_palette;
        fb_alloc_cmap(&info->cmap, 256, 0);
index 9849549..2ab65c9 100644 (file)
@@ -30,7 +30,7 @@ config W1_DS9490
          This support is also available as a module.  If so, the module 
          will be called ds9490r.ko.
 
-config W1_DS9490R_BRIDGE
+config W1_DS9490_BRIDGE
        tristate "DS9490R USB <-> W1 transport layer for 1-wire"
        depends on W1_DS9490
        help
index a389bdc..80725c3 100644 (file)
@@ -2,6 +2,10 @@
 # Makefile for the Dallas's 1-wire bus.
 #
 
+ifneq ($(CONFIG_NET), y)
+EXTRA_CFLAGS   += -DNETLINK_DISABLED
+endif
+
 obj-$(CONFIG_W1)       += wire.o
 wire-objs              := w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
 
index f0f26a4..887d689 100644 (file)
@@ -35,26 +35,26 @@ 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 *);
+int ds_touch_bit(struct ds_device *, u8, u8 *);
+int ds_read_byte(struct ds_device *, u8 *);
+int ds_read_bit(struct ds_device *, u8 *);
+int ds_write_byte(struct ds_device *, u8);
+int ds_write_bit(struct ds_device *, u8);
+int ds_start_pulse(struct ds_device *, int);
+int ds_set_speed(struct ds_device *, int);
+int ds_reset(struct ds_device *, struct ds_status *);
+int ds_detect(struct ds_device *, struct ds_status *);
+int ds_stop_pulse(struct ds_device *, int);
+int ds_send_data(struct ds_device *, unsigned char *, int);
+int ds_recv_data(struct ds_device *, unsigned char *, int);
+int ds_recv_status(struct ds_device *, struct ds_status *);
+struct ds_device * ds_get_device(void);
+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 int ds_send_control(struct ds_device *, u16, u16);
+static int ds_send_control_mode(struct ds_device *, u16, u16);
+static int ds_send_control_cmd(struct ds_device *, u16, u16);
 
 
 static struct usb_driver ds_driver = {
@@ -503,7 +503,7 @@ int ds_read_byte(struct ds_device *dev, u8 *byte)
        return 0;
 }
 
-inline int ds_read_block(struct ds_device *dev, u8 *buf, int len)
+int ds_read_block(struct ds_device *dev, u8 *buf, int len)
 {
        struct ds_status st;
        int err;
@@ -529,7 +529,7 @@ inline int ds_read_block(struct ds_device *dev, u8 *buf, int len)
        return err;
 }
 
-inline int ds_write_block(struct ds_device *dev, u8 *buf, int len)
+int ds_write_block(struct ds_device *dev, u8 *buf, int len)
 {
        int err;
        struct ds_status st;
@@ -727,11 +727,16 @@ void ds_disconnect(struct usb_interface *intf)
 {
        struct ds_device *dev;
        
-       dev = usb_get_intfdata (intf);
-       usb_set_intfdata (intf, NULL);
+       dev = usb_get_intfdata(intf);
+       usb_set_intfdata(intf, NULL);
 
-       while(atomic_read(&dev->refcnt))
-               schedule_timeout(HZ);
+       while (atomic_read(&dev->refcnt)) {
+               printk(KERN_INFO "Waiting for DS to become free: refcnt=%d.\n",
+                               atomic_read(&dev->refcnt));
+
+               if (msleep_interruptible(1000))
+                       flush_signals(current);
+       }
 
        usb_put_dev(dev->udev);
        kfree(dev);
index 77c37c6..f30b438 100644 (file)
@@ -151,23 +151,23 @@ struct ds_status
 
 };
 
-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);
+int ds_touch_bit(struct ds_device *, u8, u8 *);
+int ds_read_byte(struct ds_device *, u8 *);
+int ds_read_bit(struct ds_device *, u8 *);
+int ds_write_byte(struct ds_device *, u8);
+int ds_write_bit(struct ds_device *, u8);
+int ds_start_pulse(struct ds_device *, int);
+int ds_set_speed(struct ds_device *, int);
+int ds_reset(struct ds_device *, struct ds_status *);
+int ds_detect(struct ds_device *, struct ds_status *);
+int ds_stop_pulse(struct ds_device *, int);
+int ds_send_data(struct ds_device *, unsigned char *, int);
+int ds_recv_data(struct ds_device *, unsigned char *, int);
+int ds_recv_status(struct ds_device *, struct ds_status *);
+struct ds_device * ds_get_device(void);
+void ds_put_device(struct ds_device *);
+int ds_write_block(struct ds_device *, u8 *, int);
+int ds_read_block(struct ds_device *, u8 *, int);
 
 #endif /* __DSCORE_H */
 
index 44abe37..a219fd5 100644 (file)
@@ -78,11 +78,13 @@ static struct pci_driver matrox_w1_pci_driver = {
 
 struct matrox_device
 {
-       unsigned long base_addr;
-       unsigned long port_index, port_data;
+       void __iomem *base_addr;
+       void __iomem *port_index;
+       void __iomem *port_data;
        u8 data_mask;
 
-       unsigned long phys_addr, virt_addr;
+       unsigned long phys_addr;
+       void __iomem *virt_addr;
        unsigned long found;
 
        struct w1_bus_master *bus_master;
@@ -181,8 +183,7 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi
 
        dev->phys_addr = pci_resource_start(pdev, 1);
 
-       dev->virt_addr =
-               (unsigned long) ioremap_nocache(dev->phys_addr, 16384);
+       dev->virt_addr = ioremap_nocache(dev->phys_addr, 16384);
        if (!dev->virt_addr) {
                dev_err(&pdev->dev, "%s: failed to ioremap(0x%lx, %d).\n",
                        __func__, dev->phys_addr, 16384);
@@ -227,7 +228,7 @@ static void __devexit matrox_w1_remove(struct pci_dev *pdev)
 
        if (dev->found) {
                w1_remove_master_device(dev->bus_master);
-               iounmap((void *) dev->virt_addr);
+               iounmap(dev->virt_addr);
        }
        kfree(dev);
 }
index 278393f..38d7436 100644 (file)
@@ -47,9 +47,11 @@ MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
 
 static int w1_timeout = 10;
 int w1_max_slave_count = 10;
+int w1_max_slave_ttl = 10;
 
 module_param_named(timeout, w1_timeout, int, 0);
 module_param_named(max_slave_count, w1_max_slave_count, int, 0);
+module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
 
 spinlock_t w1_mlock = SPIN_LOCK_UNLOCKED;
 LIST_HEAD(w1_masters);
@@ -431,6 +433,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
                return err;
        }
 
+       sl->ttl = dev->slave_ttl;
        dev->slave_count++;
 
        memcpy(&msg.id.id, rn, sizeof(msg.id.id));
@@ -446,8 +449,13 @@ static void w1_slave_detach(struct w1_slave *sl)
        
        dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);
 
-       while (atomic_read(&sl->refcnt))
-               schedule_timeout(10);
+       while (atomic_read(&sl->refcnt)) {
+               printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
+                               sl->name, atomic_read(&sl->refcnt));
+
+               if (msleep_interruptible(1000))
+                       flush_signals(current);
+       }
 
        sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
        device_remove_file(&sl->dev, &sl->attr_name);
@@ -504,8 +512,8 @@ static void w1_search(struct w1_master *dev)
                         * All who don't sleep must send ID bit and COMPLEMENT ID bit.
                         * They actually are ANDed between all senders.
                         */
-                       id_bit = w1_read_bit(dev);
-                       comp_bit = w1_read_bit(dev);
+                       id_bit = w1_touch_bit(dev, 1);
+                       comp_bit = w1_touch_bit(dev, 1);
 
                        if (id_bit && comp_bit)
                                break;
@@ -536,7 +544,10 @@ static void w1_search(struct w1_master *dev)
                         * and make all who don't have "search_bit" in "i"'th position
                         * in it's registration number sleep.
                         */
-                       w1_write_bit(dev, search_bit);
+                       if (dev->bus_master->touch_bit)
+                               w1_touch_bit(dev, search_bit);
+                       else
+                               w1_write_bit(dev, search_bit);
 
                }
 #endif
@@ -569,7 +580,7 @@ static void w1_search(struct w1_master *dev)
                }
 
                if (slave_count == dev->slave_count &&
-                   ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) {
+                       rn && ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) {
                        w1_attach_slave_device(dev, (struct w1_reg_num *) &rn);
                }
        }
@@ -718,7 +729,7 @@ int w1_process(void *data)
                list_for_each_safe(ent, n, &dev->slist) {
                        sl = list_entry(ent, struct w1_slave, w1_slave_entry);
 
-                       if (sl && !test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) {
+                       if (sl && !test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
                                list_del (&sl->w1_slave_entry);
 
                                w1_slave_detach (sl);
@@ -726,6 +737,8 @@ int w1_process(void *data)
 
                                dev->slave_count--;
                        }
+                       else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
+                               sl->ttl = dev->slave_ttl;
                }
                up(&dev->mutex);
        }
index 54a3437..b84ecb1 100644 (file)
@@ -63,6 +63,7 @@ struct w1_slave
        atomic_t                refcnt;
        u8                      rom[9];
        u32                     flags;
+       int                     ttl;
 
        struct w1_master        *master;
        struct w1_family        *family;
@@ -99,6 +100,7 @@ struct w1_master
        struct list_head        slist;
        int                     max_slave_count, slave_count;
        unsigned long           attempts;
+       int                     slave_ttl;
        int                     initialized;
        u32                     id;
 
index 6a62d2a..a875ae7 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/delay.h>
 
 #include "w1_family.h"
 
@@ -84,8 +85,13 @@ void w1_unregister_family(struct w1_family *fent)
 
        spin_unlock(&w1_flock);
 
-       while (atomic_read(&fent->refcnt))
-               schedule_timeout(10);
+       while (atomic_read(&fent->refcnt)) {
+               printk(KERN_INFO "Waiting for family %u to become free: refcnt=%d.\n",
+                               fent->fid, atomic_read(&fent->refcnt));
+
+               if (msleep_interruptible(1000))
+                       flush_signals(current);
+       }
 }
 
 /*
index e671d40..7497ac7 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/delay.h>
 
 #include "w1.h"
 #include "w1_log.h"
@@ -32,12 +33,13 @@ extern struct device_driver w1_driver;
 extern struct bus_type w1_bus_type;
 extern struct device w1_device;
 extern int w1_max_slave_count;
+extern int w1_max_slave_ttl;
 extern struct list_head w1_masters;
 extern spinlock_t w1_mlock;
 
 extern int w1_process(void *);
 
-struct w1_master * w1_alloc_dev(u32 id, int slave_count,
+struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
              struct device_driver *driver, struct device *device)
 {
        struct w1_master *dev;
@@ -65,6 +67,7 @@ struct w1_master * w1_alloc_dev(u32 id, int slave_count,
        dev->kpid               = -1;
        dev->initialized        = 0;
        dev->id                 = id;
+       dev->slave_ttl          = slave_ttl;
 
        atomic_set(&dev->refcnt, 2);
 
@@ -86,17 +89,14 @@ struct w1_master * w1_alloc_dev(u32 id, int slave_count,
        dev->seq = 1;
        dev->nls = netlink_kernel_create(NETLINK_NFLOG, NULL);
        if (!dev->nls) {
-               printk(KERN_ERR "Failed to create new netlink socket(%u).\n",
-                       NETLINK_NFLOG);
-               memset(dev, 0, sizeof(struct w1_master));
-               kfree(dev);
-               dev = NULL;
+               printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
+                       NETLINK_NFLOG, dev->dev.bus_id);
        }
 
        err = device_register(&dev->dev);
        if (err) {
                printk(KERN_ERR "Failed to register master device. err=%d\n", err);
-               if (dev->nls->sk_socket)
+               if (dev->nls && dev->nls->sk_socket)
                        sock_release(dev->nls->sk_socket);
                memset(dev, 0, sizeof(struct w1_master));
                kfree(dev);
@@ -109,7 +109,7 @@ struct w1_master * w1_alloc_dev(u32 id, int slave_count,
 void w1_free_dev(struct w1_master *dev)
 {
        device_unregister(&dev->dev);
-       if (dev->nls->sk_socket)
+       if (dev->nls && dev->nls->sk_socket)
                sock_release(dev->nls->sk_socket);
        memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
        kfree(dev);
@@ -121,7 +121,7 @@ int w1_add_master_device(struct w1_bus_master *master)
        int retval = 0;
        struct w1_netlink_msg msg;
 
-       dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, &w1_driver, &w1_device);
+       dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device);
        if (!dev)
                return -ENOMEM;
 
@@ -179,8 +179,13 @@ void __w1_remove_master_device(struct w1_master *dev)
                         "%s: Failed to send signal to w1 kernel thread %d.\n",
                         __func__, dev->kpid);
 
-       while (atomic_read(&dev->refcnt))
-               schedule_timeout(10);
+       while (atomic_read(&dev->refcnt)) {
+               printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
+                               dev->name, atomic_read(&dev->refcnt));
+
+               if (msleep_interruptible(1000))
+                       flush_signals(current);
+       }
 
        msg.id.mst.id = dev->id;
        msg.id.mst.pid = dev->kpid;
index df9d3e7..2a82fb0 100644 (file)
@@ -26,6 +26,7 @@
 #include "w1_log.h"
 #include "w1_netlink.h"
 
+#ifndef NETLINK_DISABLED
 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
 {
        unsigned int size;
@@ -33,6 +34,9 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
        struct w1_netlink_msg *data;
        struct nlmsghdr *nlh;
 
+       if (!dev->nls)
+               return;
+
        size = NLMSG_SPACE(sizeof(struct w1_netlink_msg));
 
        skb = alloc_skb(size, GFP_ATOMIC);
@@ -53,3 +57,10 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
 nlmsg_failure:
        return;
 }
+#else
+#warning Netlink support is disabled. Please compile with NET support enabled.
+
+void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
+{
+}
+#endif
index d986c60..8ca23df 100644 (file)
@@ -59,19 +59,28 @@ static ssize_t w1_therm_read_name(struct device *dev, char *buf)
        return sprintf(buf, "%s\n", sl->name);
 }
 
+static inline int w1_convert_temp(u8 rom[9])
+{
+       int t, h;
+       
+       if (rom[1] == 0)
+               t = ((s32)rom[0] >> 1)*1000;
+       else
+               t = 1000*(-1*(s32)(0x100-rom[0]) >> 1);
+       
+       t -= 250;
+       h = 1000*((s32)rom[7] - (s32)rom[6]);
+       h /= (s32)rom[7];
+       t += h;
+
+       return t;
+}
+
 static ssize_t w1_therm_read_temp(struct device *dev, char *buf)
 {
        struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
-       s16 temp;
 
-       /* 
-        * Must be more precise.
-        */
-       temp = 0;
-       temp <<= sl->rom[1] / 2;
-       temp |= sl->rom[0] / 2;
-
-       return sprintf(buf, "%d\n", temp * 1000);
+       return sprintf(buf, "%d\n", w1_convert_temp(sl->rom));
 }
 
 static int w1_therm_check_rom(u8 rom[9])
@@ -92,7 +101,6 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
        struct w1_master *dev = sl->master;
        u8 rom[9], crc, verdict;
        int i, max_trying = 10;
-       u16 temp;
 
        atomic_inc(&sl->refcnt);
        if (down_interruptible(&sl->master->mutex)) {
@@ -120,6 +128,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
                if (!w1_reset_bus (dev)) {
                        int count = 0;
                        u8 match[9] = {W1_MATCH_ROM, };
+                       unsigned long tm;
 
                        memcpy(&match[1], (u64 *) & sl->reg_num, 8);
                        
@@ -127,24 +136,29 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
 
                        w1_write_8(dev, W1_CONVERT_TEMP);
 
-                       if (count < 10) {
-                               if (!w1_reset_bus(dev)) {
-                                       w1_write_block(dev, match, 9);
-
-                                       w1_write_8(dev, W1_READ_SCRATCHPAD);
-                                       if ((count = w1_read_block(dev, rom, 9)) != 9) {
-                                               dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
-                                       }
+                       tm = jiffies + msecs_to_jiffies(750);
+                       while(time_before(jiffies, tm)) {
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               schedule_timeout(tm-jiffies);
 
-                                       crc = w1_calc_crc8(rom, 8);
+                               if (signal_pending(current))
+                                       flush_signals(current);
+                       }
 
-                                       if (rom[8] == crc && rom[0])
-                                               verdict = 1;
+                       if (!w1_reset_bus (dev)) {
+                               w1_write_block(dev, match, 9);
+                               
+                               w1_write_8(dev, W1_READ_SCRATCHPAD);
+                               if ((count = w1_read_block(dev, rom, 9)) != 9) {
+                                       dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
                                }
+
+                               crc = w1_calc_crc8(rom, 8);
+
+                               if (rom[8] == crc && rom[0])
+                                       verdict = 1;
+
                        }
-                       else
-                               dev_warn(&dev->dev,
-                                         "18S20 doesn't respond to CONVERT_TEMP.\n");
                }
 
                if (!w1_therm_check_rom(rom))
@@ -157,12 +171,13 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
                           crc, (verdict) ? "YES" : "NO");
        if (verdict)
                memcpy(sl->rom, rom, sizeof(sl->rom));
+       else
+               dev_warn(&dev->dev, "18S20 doesn't respond to CONVERT_TEMP.\n");
+
        for (i = 0; i < 9; ++i)
                count += sprintf(buf + count, "%02x ", sl->rom[i]);
-       temp = 0;
-       temp <<= sl->rom[1] / 2;
-       temp |= sl->rom[0] / 2;
-       count += sprintf(buf + count, "t=%u\n", temp);
+       
+       count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom));
 out:
        up(&dev->mutex);
 out_dec:
index c10bc4b..6d70b40 100644 (file)
@@ -15,8 +15,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/zorro.h>
+#include <linux/bitops.h>
 #include <asm/setup.h>
-#include <asm/bitops.h>
 #include <asm/amigahw.h>
 
 #include "zorro.h"
index 87e8694..2439632 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
 #include <linux/parser.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
index 955dbef..c877569 100644 (file)
@@ -100,7 +100,7 @@ static int afs_init(void)
                goto error;
 #endif
 
-#ifdef CONFIG_KEYS
+#ifdef CONFIG_KEYS_TURNED_OFF
        ret = afs_key_register();
        if (ret < 0)
                goto error_cache;
@@ -142,7 +142,7 @@ static int afs_init(void)
  error_kafstimod:
        afs_kafstimod_stop();
  error_keys:
-#ifdef CONFIG_KEYS
+#ifdef CONFIG_KEYS_TURNED_OFF
        afs_key_unregister();
  error_cache:
 #endif
@@ -169,7 +169,7 @@ static void __exit afs_exit(void)
        afs_kafstimod_stop();
        afs_kafsasyncd_stop();
        afs_cell_purge();
-#ifdef CONFIG_KEYS
+#ifdef CONFIG_KEYS_TURNED_OFF
        afs_key_unregister();
 #endif
 #ifdef AFS_CACHING_SUPPORT
index a50096d..579e432 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/parser.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include "autofs_i.h"
 #include <linux/module.h>
 
index 955bf51..ec52a34 100644 (file)
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CIFS) += cifs.o
 
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o
index 592af83..b6c62f5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifs_fs_sb.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002
+ *   Copyright (c) International Business Machines  Corp., 2002,2004
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
 #ifndef _CIFS_FS_SB_H
 #define _CIFS_FS_SB_H
 
-#define CIFS_MOUNT_NO_PERM     1 /* do not do client vfs_perm check */
+#define CIFS_MOUNT_NO_PERM      1 /* do not do client vfs_perm check */
 #define CIFS_MOUNT_SET_UID      2 /* set current->euid in create etc. */
+#define CIFS_MOUNT_SERVER_INUM  4 /* inode numbers from uniqueid from server */
+#define CIFS_MOUNT_DIRECT_IO          8 /* do not write nor read through page cache */
 
 struct cifs_sb_info {
        struct cifsTconInfo *tcon;      /* primary mount */
index a78ed0a..b1f5248 100644 (file)
@@ -69,10 +69,12 @@ const struct smb_to_posix_error mapping_table_ERRDOS[] = {
        {ERRinvparm, -EINVAL},
        {ERRdiskfull, -ENOSPC},
        {ERRinvname, -ENOENT},
+       {ERRinvlevel,-EOPNOTSUPP},
        {ERRdirnotempty, -ENOTEMPTY},
        {ERRnotlocked, -ENOLCK},
        {ERRalreadyexists, -EEXIST},
        {ERRmoredata, -EOVERFLOW},
+       {ERReasnotsupported,-EOPNOTSUPP},
        {ErrQuota, -EDQUOT},
        {ErrNotALink, -ENOLINK},
        {ERRnetlogonNotStarted,-ENOPROTOOPT},
@@ -287,7 +289,7 @@ static const struct {
        ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, {
        ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, {
        ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, {
-       ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, {
+       ERRDOS, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED}, {
        ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, {
        ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, {
        ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, {
@@ -752,7 +754,8 @@ static const struct {
        ERRDOS, ERRnoaccess, 0xc000028e}, {
        ERRDOS, ERRnoaccess, 0xc000028f}, {
        ERRDOS, ERRnoaccess, 0xc0000290}, {
-ERRDOS, ERRbadfunc, 0xc000029c},};
+       ERRDOS, ERRbadfunc, 0xc000029c}, {
+       ERRDOS, ERRinvlevel, 0x007c0001}, };
 
 /*****************************************************************************
  Print an error message from the status code
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;
+}
+
index 8db20a0..e21f138 100644 (file)
@@ -69,6 +69,7 @@
 #define ERRpipeclosing 232
 #define ERRnotconnected 233
 #define ERRmoredata    234
+#define ERReasnotsupported 282
 #define ErrQuota 0x200         /* The operation would cause a quota limit to be exceeded. */
 #define ErrNotALink 0x201      /* A link operation was performed on a pathname that
                                   was not a link. */
index ebc69c3..22f909e 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/posix_acl_xattr.h>
 #include "cifsfs.h"
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifs_debug.h"
 
 #define MAX_EA_VALUE_SIZE 65535
-#define CIFS_XATTR_DOS_ATTRIB "user.DOSATTRIB"
+#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
 #define CIFS_XATTR_USER_PREFIX "user."
 #define CIFS_XATTR_SYSTEM_PREFIX "system."
-#define CIFS_XATTR_OS2_PREFIX "OS2." /* BB should check for this someday */
-/* also note could add check for security prefix XATTR_SECURITY_PREFIX */ 
+#define CIFS_XATTR_OS2_PREFIX "os2."
+#define CIFS_XATTR_SECURITY_PREFIX ".security"
+#define CIFS_XATTR_TRUSTED_PREFIX "trusted."
+#define XATTR_TRUSTED_PREFIX_LEN  8
+#define XATTR_SECURITY_PREFIX_LEN 9
+/* BB need to add server (Samba e.g) support for security and trusted prefix */
+  
 
 
 int cifs_removexattr(struct dentry * direntry, const char * ea_name)
@@ -128,16 +134,47 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
 
        if(ea_name == NULL) {
                cFYI(1,("Null xattr names not supported"));
-       } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) {
-               cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name));
+       } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
+               if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
+                       cFYI(1,("attempt to set cifs inode metadata"));
+               }
+               ea_name += 5; /* skip past user. prefix */
+               rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
+                       (__u16)value_size, cifs_sb->local_nls);
+       } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
+               ea_name += 4; /* skip past os2. prefix */
+               rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
+                       (__u16)value_size, cifs_sb->local_nls);
+       } else {
+               int temp; 
+               temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,
+                       strlen(POSIX_ACL_XATTR_ACCESS));
+               if (temp == 0) {
+#ifdef CONFIG_CIFS_POSIX
+                       rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
+                               (const int)value_size, ACL_TYPE_ACCESS,
+                               cifs_sb->local_nls);
+                       cFYI(1,("set POSIX ACL rc %d",rc));
+#else
+                       cFYI(1,("set POSIX ACL not supported"));
+#endif
+               } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
+#ifdef CONFIG_CIFS_POSIX
+                       rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
+                               (const int)value_size, ACL_TYPE_DEFAULT,
+                               cifs_sb->local_nls);
+                       cFYI(1,("set POSIX default ACL rc %d",rc));
+#else
+                       cFYI(1,("set default POSIX ACL not supported"));
+#endif
+               } else {
+                       cFYI(1,("illegal xattr request %s (only user namespace supported)",ea_name));
                  /* BB what if no namespace prefix? */
                  /* Should we just pass them to server, except for 
                  system and perhaps security prefixes? */
-       } else {
-               ea_name+=5; /* skip past user. prefix */
-               rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
-                       (__u16)value_size, cifs_sb->local_nls);
+               }
        }
        if (full_path)
                kfree(full_path);
        FreeXid(xid);
@@ -163,6 +200,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
        sb = direntry->d_inode->i_sb;
        if(sb == NULL)
                return -EIO;
+
        xid = GetXid();
 
        cifs_sb = CIFS_SB(sb);
@@ -177,19 +215,54 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
        }
        /* return dos attributes as pseudo xattr */
        /* return alt name if available as pseudo attr */
-       if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) {
-               cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name));
-               /* BB what if no namespace prefix? */
-               /* Should we just pass them to server, except for system? */
+       if(ea_name == NULL) {
+               cFYI(1,("Null xattr names not supported"));
+       } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
+               if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
+                       cFYI(1,("attempt to query cifs inode metadata"));
+                       /* revalidate/getattr then populate from inode */
+               } /* BB add else when above is implemented */
+               ea_name += 5; /* skip past user. prefix */
+               rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
+                       buf_size, cifs_sb->local_nls);
+       } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
+               ea_name += 4; /* skip past os2. prefix */
+               rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
+                       buf_size, cifs_sb->local_nls);
+       } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
+#ifdef CONFIG_CIFS_POSIX
+               rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
+                               ea_value, buf_size, ACL_TYPE_ACCESS, 
+                               cifs_sb->local_nls);
+#else 
+               cFYI(1,("query POSIX ACL not supported yet"));
+#endif /* CONFIG_CIFS_POSIX */
+       } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
+#ifdef CONFIG_CIFS_POSIX
+               rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
+                               ea_value, buf_size, ACL_TYPE_DEFAULT, 
+                               cifs_sb->local_nls);
+#else 
+               cFYI(1,("query POSIX default ACL not supported yet"));
+#endif
+       } else if(strncmp(ea_name,
+                 CIFS_XATTR_TRUSTED_PREFIX,XATTR_TRUSTED_PREFIX_LEN) == 0) {
+               cFYI(1,("Trusted xattr namespace not supported yet"));
+       } else if(strncmp(ea_name,
+                 CIFS_XATTR_SECURITY_PREFIX,XATTR_SECURITY_PREFIX_LEN) == 0) {
+               cFYI(1,("Security xattr namespace not supported yet"));
        } else {
-       /* We could add a check here
+               cFYI(1,("illegal xattr name request %s (only user namespace supported)",ea_name));
+       }
+
+       /* We could add an additional check for streams ie 
            if proc/fs/cifs/streamstoxattr is set then
                search server for EAs or streams to 
                returns as xattrs */
-               ea_name+=5; /* skip past user. */
-               rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
-                               buf_size, cifs_sb->local_nls);
-       }
+
+       if(rc == -EINVAL)
+               rc = -EOPNOTSUPP; 
+
        if (full_path)
                kfree(full_path);
        FreeXid(xid);
index 06a2d82..db06d38 100644 (file)
@@ -71,7 +71,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/genhd.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 
 int devfs_register_tape(const char *name)
 {
index e6c7210..ed4a207 100644 (file)
@@ -75,3 +75,36 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
        return NULL;
 }
 
+struct dentry *efs_get_parent(struct dentry *child)
+{
+       struct dentry *parent;
+       struct inode *inode;
+       efs_ino_t ino;
+       int error;
+
+       lock_kernel();
+
+       error = -ENOENT;
+       ino = efs_find_entry(child->d_inode, "..", 2);
+       if (!ino)
+               goto fail;
+
+       error = -EACCES;
+       inode = iget(child->d_inode->i_sb, ino);
+       if (!inode)
+               goto fail;
+
+       error = -ENOMEM;
+       parent = d_alloc_anon(inode);
+       if (!parent)
+               goto fail_iput;
+
+       unlock_kernel();
+       return parent;
+
+ fail_iput:
+       iput(inode);
+ fail:
+       unlock_kernel();
+       return ERR_PTR(error);
+}
index 467e34b..af4d01e 100644 (file)
@@ -95,6 +95,10 @@ static struct super_operations efs_superblock_operations = {
        .remount_fs     = efs_remount,
 };
 
+static struct export_operations efs_export_ops = {
+       .get_parent     = efs_get_parent,
+};
+
 static int __init init_efs_fs(void) {
        int err;
        printk("EFS: "EFS_VERSION" - http://aeschi.ch.eu.org/efs/\n");
@@ -278,6 +282,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
                s->s_flags |= MS_RDONLY;
        }
        s->s_op   = &efs_superblock_operations;
+       s->s_export_op = &efs_export_ops;
        root = iget(s, EFS_ROOTINODE);
        s->s_root = d_alloc_root(root);
  
index bf30cbf..64ccc7c 100644 (file)
@@ -275,7 +275,8 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
                                   "bad page in #%lu",
                                   inode->i_ino);
                        filp->f_pos += PAGE_CACHE_SIZE - offset;
-                       continue;
+                       ret = -EIO;
+                       goto done;
                }
                kaddr = page_address(page);
                if (need_revalidate) {
index 80faa86..1294f38 100644 (file)
@@ -116,7 +116,6 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
 /* inode.c */
 extern void ext2_read_inode (struct inode *);
 extern int ext2_write_inode (struct inode *, int);
-extern void ext2_put_inode (struct inode *);
 extern void ext2_delete_inode (struct inode *);
 extern int ext2_sync_inode (struct inode *);
 extern void ext2_discard_prealloc (struct inode *);
index ad8ff5f..dce337f 100644 (file)
 #include <linux/msdos_fs.h>
 #include <linux/buffer_head.h>
 
+/* this must be > 0. */
+#define FAT_MAX_CACHE  8
+
+struct fat_cache {
+       struct list_head cache_list;
+       int nr_contig;  /* number of contiguous clusters */
+       int fcluster;   /* cluster number in the file. */
+       int dcluster;   /* cluster number on disk. */
+};
+
+struct fat_cache_id {
+       unsigned int id;
+       int nr_contig;
+       int fcluster;
+       int dcluster;
+};
+
+static inline int fat_max_cache(struct inode *inode)
+{
+       return FAT_MAX_CACHE;
+}
+
+static kmem_cache_t *fat_cache_cachep;
+
+static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+{
+       struct fat_cache *cache = (struct fat_cache *)foo;
+
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+           SLAB_CTOR_CONSTRUCTOR)
+               INIT_LIST_HEAD(&cache->cache_list);
+}
+
+int __init fat_cache_init(void)
+{
+       fat_cache_cachep = kmem_cache_create("fat_cache",
+                               sizeof(struct fat_cache),
+                               0, SLAB_RECLAIM_ACCOUNT,
+                               init_once, NULL);
+       if (fat_cache_cachep == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+void __exit fat_cache_destroy(void)
+{
+       if (kmem_cache_destroy(fat_cache_cachep))
+               printk(KERN_INFO "fat_cache: not all structures were freed\n");
+}
+
+static inline struct fat_cache *fat_cache_alloc(struct inode *inode)
+{
+       return kmem_cache_alloc(fat_cache_cachep, SLAB_KERNEL);
+}
+
+static inline void fat_cache_free(struct fat_cache *cache)
+{
+       BUG_ON(!list_empty(&cache->cache_list));
+       kmem_cache_free(fat_cache_cachep, cache);
+}
+
+static inline void fat_cache_update_lru(struct inode *inode,
+                                       struct fat_cache *cache)
+{
+       if (MSDOS_I(inode)->cache_lru.next != &cache->cache_list)
+               list_move(&cache->cache_list, &MSDOS_I(inode)->cache_lru);
+}
+
+static int fat_cache_lookup(struct inode *inode, int fclus,
+                           struct fat_cache_id *cid,
+                           int *cached_fclus, int *cached_dclus)
+{
+       static struct fat_cache nohit = { .fcluster = 0, };
+
+       struct fat_cache *hit = &nohit, *p;
+       int offset = -1;
+
+       spin_lock(&MSDOS_I(inode)->cache_lru_lock);
+       list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) {
+               /* Find the cache of "fclus" or nearest cache. */
+               if (p->fcluster <= fclus && hit->fcluster < p->fcluster) {
+                       hit = p;
+                       if ((hit->fcluster + hit->nr_contig) < fclus) {
+                               offset = hit->nr_contig;
+                       } else {
+                               offset = fclus - hit->fcluster;
+                               break;
+                       }
+               }
+       }
+       if (hit != &nohit) {
+               fat_cache_update_lru(inode, hit);
+
+               cid->id = MSDOS_I(inode)->cache_valid_id;
+               cid->nr_contig = hit->nr_contig;
+               cid->fcluster = hit->fcluster;
+               cid->dcluster = hit->dcluster;
+               *cached_fclus = cid->fcluster + offset;
+               *cached_dclus = cid->dcluster + offset;
+       }
+       spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
+
+       return offset;
+}
+
+static struct fat_cache *fat_cache_merge(struct inode *inode,
+                                        struct fat_cache_id *new)
+{
+       struct fat_cache *p;
+
+       list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) {
+               /* Find the same part as "new" in cluster-chain. */
+               if (p->fcluster == new->fcluster) {
+                       BUG_ON(p->dcluster != new->dcluster);
+                       if (new->nr_contig > p->nr_contig)
+                               p->nr_contig = new->nr_contig;
+                       return p;
+               }
+       }
+       return NULL;
+}
+
+static void fat_cache_add(struct inode *inode, struct fat_cache_id *new)
+{
+       struct fat_cache *cache, *tmp;
+
+       if (new->fcluster == -1) /* dummy cache */
+               return;
+
+       spin_lock(&MSDOS_I(inode)->cache_lru_lock);
+       if (new->id != FAT_CACHE_VALID &&
+           new->id != MSDOS_I(inode)->cache_valid_id)
+               goto out;       /* this cache was invalidated */
+
+       cache = fat_cache_merge(inode, new);
+       if (cache == NULL) {
+               if (MSDOS_I(inode)->nr_caches < fat_max_cache(inode)) {
+                       MSDOS_I(inode)->nr_caches++;
+                       spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
+
+                       tmp = fat_cache_alloc(inode);
+                       spin_lock(&MSDOS_I(inode)->cache_lru_lock);
+                       cache = fat_cache_merge(inode, new);
+                       if (cache != NULL) {
+                               MSDOS_I(inode)->nr_caches--;
+                               fat_cache_free(tmp);
+                               goto out_update_lru;
+                       }
+                       cache = tmp;
+               } else {
+                       struct list_head *p = MSDOS_I(inode)->cache_lru.prev;
+                       cache = list_entry(p, struct fat_cache, cache_list);
+               }
+               cache->fcluster = new->fcluster;
+               cache->dcluster = new->dcluster;
+               cache->nr_contig = new->nr_contig;
+       }
+out_update_lru:
+       fat_cache_update_lru(inode, cache);
+out:
+       spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
+}
+
+/*
+ * Cache invalidation occurs rarely, thus the LRU chain is not updated. It
+ * fixes itself after a while.
+ */
+static void __fat_cache_inval_inode(struct inode *inode)
+{
+       struct msdos_inode_info *i = MSDOS_I(inode);
+       struct fat_cache *cache;
+
+       while (!list_empty(&i->cache_lru)) {
+               cache = list_entry(i->cache_lru.next, struct fat_cache, cache_list);
+               list_del_init(&cache->cache_list);
+               i->nr_caches--;
+               fat_cache_free(cache);
+       }
+       /* Update. The copy of caches before this id is discarded. */
+       i->cache_valid_id++;
+       if (i->cache_valid_id == FAT_CACHE_VALID)
+               i->cache_valid_id++;
+}
+
+void fat_cache_inval_inode(struct inode *inode)
+{
+       spin_lock(&MSDOS_I(inode)->cache_lru_lock);
+       __fat_cache_inval_inode(inode);
+       spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
+}
+
 int __fat_access(struct super_block *sb, int nr, int new_value)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
@@ -45,13 +236,13 @@ int __fat_access(struct super_block *sb, int nr, int new_value)
        }
        if (sbi->fat_bits == 32) {
                p_first = p_last = NULL; /* GCC needs that stuff */
-               next = CF_LE_L(((__le32 *) bh->b_data)[(first &
+               next = le32_to_cpu(((__le32 *) bh->b_data)[(first &
                    (sb->s_blocksize - 1)) >> 2]);
                /* Fscking Microsoft marketing department. Their "32" is 28. */
                next &= 0x0fffffff;
        } else if (sbi->fat_bits == 16) {
                p_first = p_last = NULL; /* GCC needs that stuff */
-               next = CF_LE_W(((__le16 *) bh->b_data)[(first &
+               next = le16_to_cpu(((__le16 *) bh->b_data)[(first &
                    (sb->s_blocksize - 1)) >> 1]);
        } else {
                p_first = &((__u8 *)bh->b_data)[first & (sb->s_blocksize - 1)];
@@ -64,10 +255,10 @@ int __fat_access(struct super_block *sb, int nr, int new_value)
        if (new_value != -1) {
                if (sbi->fat_bits == 32) {
                        ((__le32 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 2]
-                               = CT_LE_L(new_value);
+                               = cpu_to_le32(new_value);
                } else if (sbi->fat_bits == 16) {
                        ((__le16 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 1]
-                               = CT_LE_W(new_value);
+                               = cpu_to_le16(new_value);
                } else {
                        if (nr & 1) {
                                *p_first = (*p_first & 0xf) | (new_value << 4);
@@ -130,170 +321,25 @@ out:
        return next;
 }
 
-void fat_cache_init(struct super_block *sb)
+static inline int cache_contiguous(struct fat_cache_id *cid, int dclus)
 {
-       struct msdos_sb_info *sbi = MSDOS_SB(sb);
-       int count;
-
-       spin_lock_init(&sbi->cache_lock);
-
-       for (count = 0; count < FAT_CACHE_NR - 1; count++) {
-               sbi->cache_array[count].start_cluster = 0;
-               sbi->cache_array[count].next = &sbi->cache_array[count + 1];
-       }
-       sbi->cache_array[count].start_cluster = 0;
-       sbi->cache_array[count].next = NULL;
-       sbi->cache = sbi->cache_array;
+       cid->nr_contig++;
+       return ((cid->dcluster + cid->nr_contig) == dclus);
 }
 
-static void
-fat_cache_lookup(struct inode *inode, int cluster, int *f_clu, int *d_clu)
+static inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus)
 {
-       struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
-       struct fat_cache *walk;
-       int first;
-
-       BUG_ON(cluster == 0);
-       
-       first = MSDOS_I(inode)->i_start;
-       if (!first)
-               return;
-
-       spin_lock(&sbi->cache_lock);
-
-       if (MSDOS_I(inode)->disk_cluster &&
-           MSDOS_I(inode)->file_cluster <= cluster) {
-               *d_clu = MSDOS_I(inode)->disk_cluster;
-               *f_clu = MSDOS_I(inode)->file_cluster;
-       }
-
-       for (walk = sbi->cache; walk; walk = walk->next) {
-               if (walk->start_cluster == first
-                   && walk->file_cluster <= cluster
-                   && walk->file_cluster > *f_clu) {
-                       *d_clu = walk->disk_cluster;
-                       *f_clu = walk->file_cluster;
-#ifdef DEBUG
-                       printk("cache hit: %d (%d)\n", *f_clu, *d_clu);
-#endif
-                       if (*f_clu == cluster)
-                               goto out;
-               }
-       }
-#ifdef DEBUG
-       printk("cache miss\n");
-#endif
-out:
-       spin_unlock(&sbi->cache_lock);
-}
-
-#ifdef DEBUG
-static void list_cache(struct super_block *sb)
-{
-       struct msdos_sb_info *sbi = MSDOS_SB(sb);
-       struct fat_cache *walk;
-
-       for (walk = sbi->cache; walk; walk = walk->next) {
-               if (walk->start_cluster)
-                       printk("<%s,%d>(%d,%d) ", sb->s_id,
-                              walk->start_cluster, walk->file_cluster,
-                              walk->disk_cluster);
-               else
-                       printk("-- ");
-       }
-       printk("\n");
-}
-#endif
-
-/*
- * Cache invalidation occurs rarely, thus the LRU chain is not updated. It
- * fixes itself after a while.
- */
-static void __fat_cache_inval_inode(struct inode *inode)
-{
-       struct fat_cache *walk;
-       int first = MSDOS_I(inode)->i_start;
-       MSDOS_I(inode)->file_cluster = MSDOS_I(inode)->disk_cluster = 0;
-       for (walk = MSDOS_SB(inode->i_sb)->cache; walk; walk = walk->next)
-               if (walk->start_cluster == first)
-                       walk->start_cluster = 0;
-}
-
-void fat_cache_inval_inode(struct inode *inode)
-{
-       struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
-       spin_lock(&sbi->cache_lock);
-       __fat_cache_inval_inode(inode);
-       spin_unlock(&sbi->cache_lock);
-}
-
-void fat_cache_add(struct inode *inode, int f_clu, int d_clu)
-{
-       struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
-       struct fat_cache *walk, *last;
-       int first, prev_f_clu, prev_d_clu;
-
-       if (f_clu == 0)
-               return;
-       first = MSDOS_I(inode)->i_start;
-       if (!first)
-               return;
-
-       last = NULL;
-       spin_lock(&sbi->cache_lock);
-
-       if (MSDOS_I(inode)->file_cluster == f_clu)
-               goto out;
-       else {
-               prev_f_clu = MSDOS_I(inode)->file_cluster;
-               prev_d_clu = MSDOS_I(inode)->disk_cluster;
-               MSDOS_I(inode)->file_cluster = f_clu;
-               MSDOS_I(inode)->disk_cluster = d_clu;
-               if (prev_f_clu == 0)
-                       goto out;
-               f_clu = prev_f_clu;
-               d_clu = prev_d_clu;
-       }
-       
-       for (walk = sbi->cache; walk->next; walk = (last = walk)->next) {
-               if (walk->start_cluster == first &&
-                   walk->file_cluster == f_clu) {
-                       if (walk->disk_cluster != d_clu) {
-                               printk(KERN_ERR "FAT: cache corruption "
-                                      "(i_pos %lld)\n", MSDOS_I(inode)->i_pos);
-                               __fat_cache_inval_inode(inode);
-                               goto out;
-                       }
-                       if (last == NULL)
-                               goto out;
-
-                       /* update LRU */
-                       last->next = walk->next;
-                       walk->next = sbi->cache;
-                       sbi->cache = walk;
-#ifdef DEBUG
-                       list_cache();
-#endif
-                       goto out;
-               }
-       }
-       walk->start_cluster = first;
-       walk->file_cluster = f_clu;
-       walk->disk_cluster = d_clu;
-       last->next = NULL;
-       walk->next = sbi->cache;
-       sbi->cache = walk;
-#ifdef DEBUG
-       list_cache();
-#endif
-out:
-       spin_unlock(&sbi->cache_lock);
+       cid->id = FAT_CACHE_VALID;
+       cid->fcluster = fclus;
+       cid->dcluster = dclus;
+       cid->nr_contig = 0;
 }
 
 int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
 {
        struct super_block *sb = inode->i_sb;
        const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits;
+       struct fat_cache_id cid;
        int nr;
 
        BUG_ON(MSDOS_I(inode)->i_start == 0);
@@ -303,7 +349,14 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
        if (cluster == 0)
                return 0;
 
-       fat_cache_lookup(inode, cluster, fclus, dclus);
+       if (fat_cache_lookup(inode, cluster, &cid, fclus, dclus) < 0) {
+               /*
+                * dummy, always not contiguous
+                * This is reinitialized by cache_init(), later.
+                */
+               cache_init(&cid, -1, -1);
+       }
+
        while (*fclus < cluster) {
                /* prevent the infinite loop of cluster chain */
                if (*fclus > limit) {
@@ -322,13 +375,15 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
                                     MSDOS_I(inode)->i_pos);
                        return -EIO;
                } else if (nr == FAT_ENT_EOF) {
-                       fat_cache_add(inode, *fclus, *dclus);
+                       fat_cache_add(inode, &cid);
                        return FAT_ENT_EOF;
                }
                (*fclus)++;
                *dclus = nr;
+               if (!cache_contiguous(&cid, *dclus))
+                       cache_init(&cid, *fclus, *dclus);
        }
-       fat_cache_add(inode, *fclus, *dclus);
+       fat_cache_add(inode, &cid);
        return 0;
 }
 
index 85a85ec..d6f149c 100644 (file)
@@ -69,7 +69,8 @@ void fat_clusters_flush(struct super_block *sb)
                printk(KERN_ERR "FAT: Did not find valid FSINFO signature.\n"
                       "     Found signature1 0x%08x signature2 0x%08x"
                       " (sector = %lu)\n",
-                      CF_LE_L(fsinfo->signature1), CF_LE_L(fsinfo->signature2),
+                      le32_to_cpu(fsinfo->signature1),
+                      le32_to_cpu(fsinfo->signature2),
                       sbi->fsinfo_sector);
        } else {
                if (sbi->free_clusters != -1)
@@ -155,7 +156,7 @@ int fat_add_cluster(struct inode *inode)
                ret = fat_access(sb, last, new_dclus);
                if (ret < 0)
                        return ret;
-               fat_cache_add(inode, new_fclus, new_dclus);
+//             fat_cache_add(inode, new_fclus, new_dclus);
        } else {
                MSDOS_I(inode)->i_start = new_dclus;
                MSDOS_I(inode)->i_logstart = new_dclus;
index 276be78..af0fd49 100644 (file)
@@ -6,6 +6,7 @@
  *  table of configured filesystems
  */
 
+#include <linux/syscalls.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
index fa13214..c41f5a8 100644 (file)
@@ -5,6 +5,6 @@
 obj-$(CONFIG_HFS_FS) += hfs.o
 
 hfs-objs := bitmap.o bfind.o bnode.o brec.o btree.o \
-           catalog.o dir.o extent.o inode.o mdb.o \
+           catalog.o dir.o extent.o inode.o attr.o mdb.o \
             part_tbl.o string.o super.o sysdep.o trans.o
 
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;
+}
index 64354de..394725e 100644 (file)
@@ -201,10 +201,12 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
                res = hfs_extend_file(inode);
                if (res)
                        return ERR_PTR(res);
-               inode->i_blocks = HFS_I(inode)->alloc_blocks *
-                                 HFS_SB(tree->sb)->fs_div;
                HFS_I(inode)->phys_size = inode->i_size =
-                       (loff_t)inode->i_blocks << tree->sb->s_blocksize_bits;
+                               (loff_t)HFS_I(inode)->alloc_blocks *
+                               HFS_SB(tree->sb)->alloc_blksz;
+               HFS_I(inode)->fs_blocks = inode->i_size >>
+                                         tree->sb->s_blocksize_bits;
+               inode_set_bytes(inode, inode->i_size);
                count = inode->i_size >> tree->node_size_shift;
                tree->free_nodes = count - tree->node_count;
                tree->node_count = count;
index 6106ab6..dc1a738 100644 (file)
@@ -306,6 +306,9 @@ int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        res = hfs_cat_move(old_dentry->d_inode->i_ino,
                           old_dir, &old_dentry->d_name,
                           new_dir, &new_dentry->d_name);
+       if (!res)
+               hfs_cat_build_key((btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
+                                 new_dir->i_ino, &new_dentry->d_name);
        return res;
 }
 
index b7ce3f0..2ea3c89 100644 (file)
@@ -328,8 +328,8 @@ int hfs_get_block(struct inode *inode, sector_t block,
        /* Convert inode block to disk allocation block */
        ablock = (u32)block / HFS_SB(sb)->fs_div;
 
-       if (block >= inode->i_blocks) {
-               if (block > inode->i_blocks || !create)
+       if (block >= HFS_I(inode)->fs_blocks) {
+               if (block > HFS_I(inode)->fs_blocks || !create)
                        return -EIO;
                if (ablock >= HFS_I(inode)->alloc_blocks) {
                        res = hfs_extend_file(inode);
@@ -363,7 +363,8 @@ done:
        if (create) {
                set_buffer_new(bh_result);
                HFS_I(inode)->phys_size += sb->s_blocksize;
-               inode->i_blocks++;
+               HFS_I(inode)->fs_blocks++;
+               inode_add_bytes(inode, sb->s_blocksize);
                mark_inode_dirty(inode);
        }
        return 0;
@@ -521,6 +522,7 @@ void hfs_file_truncate(struct inode *inode)
        HFS_I(inode)->alloc_blocks = blk_cnt;
 out:
        HFS_I(inode)->phys_size = inode->i_size;
+       HFS_I(inode)->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+       inode_set_bytes(inode, HFS_I(inode)->fs_blocks << sb->s_blocksize_bits);
        mark_inode_dirty(inode);
-       inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
 }
index ecf33d8..03634a3 100644 (file)
@@ -60,6 +60,7 @@ struct hfs_inode_info {
        struct semaphore extents_lock;
 
        u16 alloc_blocks, clump_blocks;
+       sector_t fs_blocks;
        /* Allocation extents from catlog record or volume header */
        hfs_extent_rec first_extents;
        u16 first_blocks;
@@ -206,6 +207,13 @@ extern struct inode *hfs_iget(struct super_block *, struct hfs_cat_key *, hfs_ca
 extern void hfs_clear_inode(struct inode *);
 extern void hfs_delete_inode(struct inode *);
 
+/* attr.c */
+extern int hfs_setxattr(struct dentry *dentry, const char *name,
+                       const void *value, size_t size, int flags);
+extern ssize_t hfs_getxattr(struct dentry *dentry, const char *name,
+                           void *value, size_t size);
+extern ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+
 /* mdb.c */
 extern int hfs_mdb_get(struct super_block *);
 extern void hfs_mdb_commit(struct super_block *);
index f90764f..4efb640 100644 (file)
@@ -200,8 +200,7 @@ int hfs_mdb_get(struct super_block *sb)
        }
 
        attrib = mdb->drAtrb;
-       if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))
-           || (attrib & cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT))) {
+       if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) {
                hfs_warn("HFS-fs warning: Filesystem was not cleanly unmounted, "
                         "running fsck.hfs is recommended.  mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
@@ -212,8 +211,9 @@ int hfs_mdb_get(struct super_block *sb)
        }
        if (!(sb->s_flags & MS_RDONLY)) {
                /* Mark the volume uncleanly unmounted in case we crash */
-               mdb->drAtrb = attrib & cpu_to_be16(~HFS_SB_ATTRIB_UNMNT);
-               mdb->drAtrb = attrib | cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT);
+               attrib &= cpu_to_be16(~HFS_SB_ATTRIB_UNMNT);
+               attrib |= cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT);
+               mdb->drAtrb = attrib;
                mdb->drWrCnt = cpu_to_be32(be32_to_cpu(mdb->drWrCnt) + 1);
                mdb->drLsMod = hfs_mtime();
 
index 25119fd..44326aa 100644 (file)
@@ -187,10 +187,12 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
                res = hfsplus_file_extend(inode);
                if (res)
                        return ERR_PTR(res);
-               inode->i_blocks = HFSPLUS_I(inode).alloc_blocks <<
-                                 HFSPLUS_SB(tree->sb).fs_shift;
                HFSPLUS_I(inode).phys_size = inode->i_size =
-                       (loff_t)inode->i_blocks << tree->sb->s_blocksize_bits;
+                               (loff_t)HFSPLUS_I(inode).alloc_blocks <<
+                               HFSPLUS_SB(tree->sb).alloc_blksz_shift;
+               HFSPLUS_I(inode).fs_blocks = HFSPLUS_I(inode).alloc_blocks <<
+                                            HFSPLUS_SB(tree->sb).fs_shift;
+               inode_set_bytes(inode, inode->i_size);
                count = inode->i_size >> tree->node_size_shift;
                tree->free_nodes = count - tree->node_count;
                tree->node_count = count;
index 51d4b12..bfc8657 100644 (file)
@@ -183,8 +183,8 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
        shift = HFSPLUS_SB(sb).alloc_blksz_shift - sb->s_blocksize_bits;
        ablock = iblock >> HFSPLUS_SB(sb).fs_shift;
 
-       if (iblock >= inode->i_blocks) {
-               if (iblock > inode->i_blocks || !create)
+       if (iblock >= HFSPLUS_I(inode).fs_blocks) {
+               if (iblock > HFSPLUS_I(inode).fs_blocks || !create)
                        return -EIO;
                if (ablock >= HFSPLUS_I(inode).alloc_blocks) {
                        res = hfsplus_file_extend(inode);
@@ -217,7 +217,8 @@ done:
        if (create) {
                set_buffer_new(bh_result);
                HFSPLUS_I(inode).phys_size += sb->s_blocksize;
-               inode->i_blocks++;
+               HFSPLUS_I(inode).fs_blocks++;
+               inode_add_bytes(inode, sb->s_blocksize);
                mark_inode_dirty(inode);
        }
        return 0;
@@ -497,6 +498,7 @@ void hfsplus_file_truncate(struct inode *inode)
        HFSPLUS_I(inode).alloc_blocks = blk_cnt;
 out:
        HFSPLUS_I(inode).phys_size = inode->i_size;
+       HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+       inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits);
        mark_inode_dirty(inode);
-       inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
 }
index 57b6ec7..4d976d2 100644 (file)
@@ -155,6 +155,7 @@ struct hfsplus_sb_info {
 struct hfsplus_inode_info {
        struct semaphore extents_lock;
        u32 clump_blocks, alloc_blocks;
+       sector_t fs_blocks;
        /* Allocation extents from catalog record or volume header */
        hfsplus_extent_rec first_extents;
        u32 first_blocks;
@@ -340,6 +341,11 @@ void hfsplus_delete_inode(struct inode *);
 /* ioctl.c */
 int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                  unsigned long arg);
+int hfsplus_setxattr(struct dentry *dentry, const char *name,
+                    const void *value, size_t size, int flags);
+ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
+                        void *value, size_t size);
+ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
 
 /* options.c */
 int parse_options(char *, struct hfsplus_sb_info *);
index 4ff176a..09242d5 100644 (file)
@@ -246,8 +246,7 @@ int hfsplus_remount(struct super_block *sb, int *flags, char *data)
        if (!(*flags & MS_RDONLY)) {
                struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
 
-               if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_INCNSTNT)) ||
-                   !(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
+               if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
                        printk("HFS+-fs warning: Filesystem was not cleanly unmounted, "
                               "running fsck.hfsplus is recommended.  leaving read-only.\n");
                        sb->s_flags |= MS_RDONLY;
@@ -332,8 +331,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op = &hfsplus_sops;
        sb->s_maxbytes = MAX_LFS_FILESIZE;
 
-       if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_INCNSTNT)) ||
-           !(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
+       if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
                if (!silent)
                        printk("HFS+-fs warning: Filesystem was not cleanly unmounted, "
                               "running fsck.hfsplus is recommended.  mounting read-only.\n");
index 2615ad1..85c8741 100644 (file)
@@ -616,7 +616,6 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction)
        J_ASSERT(transaction->t_log_list == NULL);
        J_ASSERT(transaction->t_checkpoint_list == NULL);
        J_ASSERT(transaction->t_updates == 0);
-       J_ASSERT(list_empty(&transaction->t_jcb));
        J_ASSERT(journal->j_committing_transaction != transaction);
        J_ASSERT(journal->j_running_transaction != transaction);
 
index 561e37f..0ec0be3 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir.c,v 1.82 2003/10/11 11:47:23 dwmw2 Exp $
+ * $Id: dir.c,v 1.83 2004/10/19 07:48:44 havasi Exp $
  *
  */
 
@@ -217,7 +217,6 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
                              dentry->d_name.name, dentry->d_name.len);
 
        if (ret) {
-               jffs2_clear_inode(inode);
                make_bad_inode(inode);
                iput(inode);
                jffs2_free_raw_inode(ri);
index b3388df..580a325 100644 (file)
@@ -39,22 +39,22 @@ struct dinode {
         *
         * define generic/POSIX attributes
         */
-       u32 di_inostamp;        /* 4: stamp to show inode belongs to fileset */
-       s32 di_fileset;         /* 4: fileset number */
-       u32 di_number;          /* 4: inode number, aka file serial number */
-       u32 di_gen;             /* 4: inode generation number */
+       __le32 di_inostamp;     /* 4: stamp to show inode belongs to fileset */
+       __le32 di_fileset;      /* 4: fileset number */
+       __le32 di_number;       /* 4: inode number, aka file serial number */
+       __le32 di_gen;          /* 4: inode generation number */
 
        pxd_t di_ixpxd;         /* 8: inode extent descriptor */
 
-       s64 di_size;            /* 8: size */
-       s64 di_nblocks;         /* 8: number of blocks allocated */
+       __le64 di_size;         /* 8: size */
+       __le64 di_nblocks;      /* 8: number of blocks allocated */
 
-       u32 di_nlink;           /* 4: number of links to the object */
+       __le32 di_nlink;        /* 4: number of links to the object */
 
-       u32 di_uid;             /* 4: user id of owner */
-       u32 di_gid;             /* 4: group id of owner */
+       __le32 di_uid;          /* 4: user id of owner */
+       __le32 di_gid;          /* 4: group id of owner */
 
-       u32 di_mode;            /* 4: attribute, format and permission */
+       __le32 di_mode;         /* 4: attribute, format and permission */
 
        struct timestruc_t di_atime;    /* 8: time last data accessed */
        struct timestruc_t di_ctime;    /* 8: time last status changed */
@@ -65,9 +65,9 @@ struct dinode {
 
        dxd_t di_ea;            /* 16: ea descriptor */
 
-       u32 di_next_index;      /* 4: Next available dir_table index */
+       __le32 di_next_index;   /* 4: Next available dir_table index */
 
-       s32 di_acltype;         /* 4: Type of ACL */
+       __le32 di_acltype;      /* 4: Type of ACL */
 
        /*
         *      Extension Areas.
@@ -103,7 +103,7 @@ struct dinode {
                                u8 _data[96];           /* 96: unused */
                                struct {
                                        void *_imap;    /* 4: unused */
-                                       u32 _gengen;    /* 4: generator */
+                                       __le32 _gengen; /* 4: generator */
                                } _imap;
                        } _u1;                          /* 96: */
 #define di_gengen      u._file._u1._imap._gengen
@@ -114,7 +114,7 @@ struct dinode {
                                        u8 unused[16];  /* 16: */
                                        dxd_t _dxd;     /* 16: */
                                        union {
-                                               u32 _rdev;      /* 4: */
+                                               __le32 _rdev;   /* 4: */
                                                u8 _fastsymlink[128];
                                        } _u;
                                        u8 _inlineea[128];
index 9599b9f..32e2588 100644 (file)
@@ -145,10 +145,10 @@ static __inline signed char TREEMAX(signed char *cp)
  * dmaptree must be consistent with dmapctl.
  */
 struct dmaptree {
-       s32 nleafs;             /* 4: number of tree leafs      */
-       s32 l2nleafs;           /* 4: l2 number of tree leafs   */
-       s32 leafidx;            /* 4: index of first tree leaf  */
-       s32 height;             /* 4: height of the tree        */
+       __le32 nleafs;          /* 4: number of tree leafs      */
+       __le32 l2nleafs;        /* 4: l2 number of tree leafs   */
+       __le32 leafidx;         /* 4: index of first tree leaf  */
+       __le32 height;          /* 4: height of the tree        */
        s8 budmin;              /* 1: min l2 tree leaf value to combine */
        s8 stree[TREESIZE];     /* TREESIZE: tree               */
        u8 pad[2];              /* 2: pad to word boundary      */
@@ -158,13 +158,13 @@ struct dmaptree {
  *     dmap page per 8K blocks bitmap
  */
 struct dmap {
-       s32 nblocks;            /* 4: num blks covered by this dmap     */
-       s32 nfree;              /* 4: num of free blks in this dmap     */
-       s64 start;              /* 8: starting blkno for this dmap      */
+       __le32 nblocks;         /* 4: num blks covered by this dmap     */
+       __le32 nfree;           /* 4: num of free blks in this dmap     */
+       __le64 start;           /* 8: starting blkno for this dmap      */
        struct dmaptree tree;   /* 360: dmap tree                       */
        u8 pad[1672];           /* 1672: pad to 2048 bytes              */
-       u32 wmap[LPERDMAP];     /* 1024: bits of the working map        */
-       u32 pmap[LPERDMAP];     /* 1024: bits of the persistent map     */
+       __le32 wmap[LPERDMAP];  /* 1024: bits of the working map        */
+       __le32 pmap[LPERDMAP];  /* 1024: bits of the persistent map     */
 };                             /* - 4096 -                             */
 
 /*
@@ -173,10 +173,10 @@ struct dmap {
  * dmapctl must be consistent with dmaptree.
  */
 struct dmapctl {
-       s32 nleafs;             /* 4: number of tree leafs      */
-       s32 l2nleafs;           /* 4: l2 number of tree leafs   */
-       s32 leafidx;            /* 4: index of the first tree leaf      */
-       s32 height;             /* 4: height of tree            */
+       __le32 nleafs;          /* 4: number of tree leafs      */
+       __le32 l2nleafs;        /* 4: l2 number of tree leafs   */
+       __le32 leafidx;         /* 4: index of the first tree leaf      */
+       __le32 height;          /* 4: height of tree            */
        s8 budmin;              /* 1: minimum l2 tree leaf value        */
        s8 stree[CTLTREESIZE];  /* CTLTREESIZE: dmapctl tree    */
        u8 pad[2714];           /* 2714: pad to 4096            */
@@ -201,30 +201,47 @@ typedef union dmtree {
 /* 
  *     on-disk aggregate disk allocation map descriptor.
  */
-struct dbmap {
-       s64 dn_mapsize;         /* 8: number of blocks in aggregate     */
-       s64 dn_nfree;           /* 8: num free blks in aggregate map    */
-       s32 dn_l2nbperpage;     /* 4: number of blks per page           */
-       s32 dn_numag;           /* 4: total number of ags               */
-       s32 dn_maxlevel;        /* 4: number of active ags              */
-       s32 dn_maxag;           /* 4: max active alloc group number     */
-       s32 dn_agpref;          /* 4: preferred alloc group (hint)      */
-       s32 dn_aglevel;         /* 4: dmapctl level holding the AG      */
-       s32 dn_agheigth;        /* 4: height in dmapctl of the AG       */
-       s32 dn_agwidth;         /* 4: width in dmapctl of the AG        */
-       s32 dn_agstart;         /* 4: start tree index at AG height     */
-       s32 dn_agl2size;        /* 4: l2 num of blks per alloc group    */
-       s64 dn_agfree[MAXAG];   /* 8*MAXAG: per AG free count           */
-       s64 dn_agsize;          /* 8: num of blks per alloc group       */
+struct dbmap_disk {
+       __le64 dn_mapsize;      /* 8: number of blocks in aggregate     */
+       __le64 dn_nfree;        /* 8: num free blks in aggregate map    */
+       __le32 dn_l2nbperpage;  /* 4: number of blks per page           */
+       __le32 dn_numag;        /* 4: total number of ags               */
+       __le32 dn_maxlevel;     /* 4: number of active ags              */
+       __le32 dn_maxag;        /* 4: max active alloc group number     */
+       __le32 dn_agpref;       /* 4: preferred alloc group (hint)      */
+       __le32 dn_aglevel;      /* 4: dmapctl level holding the AG      */
+       __le32 dn_agheigth;     /* 4: height in dmapctl of the AG       */
+       __le32 dn_agwidth;      /* 4: width in dmapctl of the AG        */
+       __le32 dn_agstart;      /* 4: start tree index at AG height     */
+       __le32 dn_agl2size;     /* 4: l2 num of blks per alloc group    */
+       __le64 dn_agfree[MAXAG];/* 8*MAXAG: per AG free count           */
+       __le64 dn_agsize;       /* 8: num of blks per alloc group       */
        s8 dn_maxfreebud;       /* 1: max free buddy system             */
        u8 pad[3007];           /* 3007: pad to 4096                    */
 };                             /* - 4096 -                             */
 
+struct dbmap {
+       s64 dn_mapsize;         /* number of blocks in aggregate     */
+       s64 dn_nfree;           /* num free blks in aggregate map    */
+       int dn_l2nbperpage;     /* number of blks per page           */
+       int dn_numag;           /* total number of ags               */
+       int dn_maxlevel;        /* number of active ags              */
+       int dn_maxag;           /* max active alloc group number     */
+       int dn_agpref;          /* preferred alloc group (hint)      */
+       int dn_aglevel;         /* dmapctl level holding the AG      */
+       int dn_agheigth;        /* height in dmapctl of the AG       */
+       int dn_agwidth;         /* width in dmapctl of the AG        */
+       int dn_agstart;         /* start tree index at AG height     */
+       int dn_agl2size;        /* l2 num of blks per alloc group    */
+       s64 dn_agfree[MAXAG];   /* per AG free count           */
+       s64 dn_agsize;          /* num of blks per alloc group       */
+       signed char dn_maxfreebud;      /* max free buddy system             */
+};                             /* - 4096 -                             */
 /* 
  *     in-memory aggregate disk allocation map descriptor.
  */
 struct bmap {
-       struct dbmap db_bmap;   /* on-disk aggregate map descriptor */
+       struct dbmap db_bmap;           /* on-disk aggregate map descriptor */
        struct inode *db_ipbmap;        /* ptr to aggregate map incore inode */
        struct semaphore db_bmaplock;   /* aggregate map lock */
        atomic_t db_active[MAXAG];      /* count of active, open files in AG */
index d7bc0cf..273a801 100644 (file)
@@ -47,7 +47,7 @@ typedef union {
 struct dtslot {
        s8 next;                /* 1: */
        s8 cnt;                 /* 1: */
-       wchar_t name[15];       /* 30: */
+       __le16 name[15];        /* 30: */
 };                             /* (32) */
 
 
@@ -67,7 +67,7 @@ struct idtentry {
 
        s8 next;                /* 1: */
        u8 namlen;              /* 1: */
-       wchar_t name[11];       /* 22: 2-byte aligned */
+       __le16 name[11];        /* 22: 2-byte aligned */
 };                             /* (32) */
 
 #define DTIHDRSIZE     10
@@ -83,11 +83,11 @@ struct idtentry {
  *     For legacy filesystems, name contains 13 wchars -- no index field
  */
 struct ldtentry {
-       u32 inumber;            /* 4: 4-byte aligned */
+       __le32 inumber;         /* 4: 4-byte aligned */
        s8 next;                /* 1: */
        u8 namlen;              /* 1: */
-       wchar_t name[11];       /* 22: 2-byte aligned */
-       u32 index;              /* 4: index into dir_table */
+       __le16 name[11];        /* 22: 2-byte aligned */
+       __le32 index;           /* 4: index into dir_table */
 };                             /* (32) */
 
 #define DTLHDRSIZE     6
@@ -113,7 +113,7 @@ struct dir_table_slot {
        u8 flag;                /* 1: 0 if free */
        u8 slot;                /* 1: slot within leaf page of entry */
        u8 addr1;               /* 1: upper 8 bits of leaf page address */
-       u32 addr2;              /* 4: lower 32 bits of leaf page address -OR-
+       __le32 addr2;           /* 4: lower 32 bits of leaf page address -OR-
                                   index of next entry when this entry was deleted */
 };                             /* (8) */
 
@@ -151,7 +151,7 @@ typedef union {
                s8 freecnt;     /* 1: free count */
                s8 freelist;    /* 1: freelist header */
 
-               u32 idotdot;    /* 4: parent inode number */
+               __le32 idotdot; /* 4: parent inode number */
 
                s8 stbl[8];     /* 8: sorted entry index table */
        } header;               /* (32) */
@@ -192,8 +192,8 @@ typedef union {
  */
 typedef union {
        struct {
-               s64 next;       /* 8: next sibling */
-               s64 prev;       /* 8: previous sibling */
+               __le64 next;    /* 8: next sibling */
+               __le64 prev;    /* 8: previous sibling */
 
                u8 flag;        /* 1: */
                u8 nextindex;   /* 1: next entry index in stbl */
index 4125587..6b59ade 100644 (file)
  *     inode allocation group page (per 4096 inodes of an AG)
  */
 struct iag {
-       s64 agstart;            /* 8: starting block of ag              */
-       s32 iagnum;             /* 4: inode allocation group number     */
-       s32 inofreefwd;         /* 4: ag inode free list forward        */
-       s32 inofreeback;        /* 4: ag inode free list back           */
-       s32 extfreefwd;         /* 4: ag inode extent free list forward */
-       s32 extfreeback;        /* 4: ag inode extent free list back    */
-       s32 iagfree;            /* 4: iag free list                     */
+       __le64 agstart;         /* 8: starting block of ag              */
+       __le32 iagnum;          /* 4: inode allocation group number     */
+       __le32 inofreefwd;      /* 4: ag inode free list forward        */
+       __le32 inofreeback;     /* 4: ag inode free list back           */
+       __le32 extfreefwd;      /* 4: ag inode extent free list forward */
+       __le32 extfreeback;     /* 4: ag inode extent free list back    */
+       __le32 iagfree;         /* 4: iag free list                     */
 
        /* summary map: 1 bit per inode extent */
-       s32 inosmap[SMAPSZ];    /* 16: sum map of mapwords w/ free inodes;
+       __le32 inosmap[SMAPSZ]; /* 16: sum map of mapwords w/ free inodes;
                                 *      note: this indicates free and backed
                                 *      inodes, if the extent is not backed the
                                 *      value will be 1.  if the extent is
@@ -78,43 +78,61 @@ struct iag {
                                 *      backed but at least one of the inodes is
                                 *      free the value will be 0.
                                 */
-       s32 extsmap[SMAPSZ];    /* 16: sum map of mapwords w/ free extents */
-       s32 nfreeinos;          /* 4: number of free inodes             */
-       s32 nfreeexts;          /* 4: number of free extents            */
+       __le32 extsmap[SMAPSZ]; /* 16: sum map of mapwords w/ free extents */
+       __le32 nfreeinos;               /* 4: number of free inodes             */
+       __le32 nfreeexts;               /* 4: number of free extents            */
        /* (72) */
        u8 pad[1976];           /* 1976: pad to 2048 bytes */
        /* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */
-       u32 wmap[EXTSPERIAG];   /* 512: working allocation map  */
-       u32 pmap[EXTSPERIAG];   /* 512: persistent allocation map */
+       __le32 wmap[EXTSPERIAG];        /* 512: working allocation map  */
+       __le32 pmap[EXTSPERIAG];        /* 512: persistent allocation map */
        pxd_t inoext[EXTSPERIAG];       /* 1024: inode extent addresses */
 };                             /* (4096) */
 
 /*
  *     per AG control information (in inode map control page)
  */
-struct iagctl {
-       s32 inofree;            /* 4: free inode list anchor            */
-       s32 extfree;            /* 4: free extent list anchor           */
-       s32 numinos;            /* 4: number of backed inodes           */
-       s32 numfree;            /* 4: number of free inodes             */
+struct iagctl_disk {
+       __le32 inofree;         /* 4: free inode list anchor            */
+       __le32 extfree;         /* 4: free extent list anchor           */
+       __le32 numinos;         /* 4: number of backed inodes           */
+       __le32 numfree;         /* 4: number of free inodes             */
 };                             /* (16) */
 
+struct iagctl {
+       int inofree;            /* free inode list anchor            */
+       int extfree;            /* free extent list anchor           */
+       int numinos;            /* number of backed inodes           */
+       int numfree;            /* number of free inodes             */
+};
+
 /*
  *     per fileset/aggregate inode map control page
  */
-struct dinomap {
-       s32 in_freeiag;         /* 4: free iag list anchor     */
-       s32 in_nextiag;         /* 4: next free iag number     */
-       s32 in_numinos;         /* 4: num of backed inodes */
-       s32 in_numfree;         /* 4: num of free backed inodes */
-       s32 in_nbperiext;       /* 4: num of blocks per inode extent */
-       s32 in_l2nbperiext;     /* 4: l2 of in_nbperiext */
-       s32 in_diskblock;       /* 4: for standalone test driver  */
-       s32 in_maxag;           /* 4: for standalone test driver  */
+struct dinomap_disk {
+       __le32 in_freeiag;      /* 4: free iag list anchor     */
+       __le32 in_nextiag;      /* 4: next free iag number     */
+       __le32 in_numinos;      /* 4: num of backed inodes */
+       __le32 in_numfree;      /* 4: num of free backed inodes */
+       __le32 in_nbperiext;    /* 4: num of blocks per inode extent */
+       __le32 in_l2nbperiext;  /* 4: l2 of in_nbperiext */
+       __le32 in_diskblock;    /* 4: for standalone test driver  */
+       __le32 in_maxag;        /* 4: for standalone test driver  */
        u8 pad[2016];           /* 2016: pad to 2048 */
-       struct iagctl in_agctl[MAXAG];  /* 2048: AG control information */
+       struct iagctl_disk in_agctl[MAXAG]; /* 2048: AG control information */
 };                             /* (4096) */
 
+struct dinomap {
+       int in_freeiag;         /* free iag list anchor     */
+       int in_nextiag;         /* next free iag number     */
+       int in_numinos;         /* num of backed inodes */
+       int in_numfree;         /* num of free backed inodes */
+       int in_nbperiext;       /* num of blocks per inode extent */
+       int in_l2nbperiext;     /* l2 of in_nbperiext */
+       int in_diskblock;       /* for standalone test driver  */
+       int in_maxag;           /* for standalone test driver  */
+       struct iagctl in_agctl[MAXAG];  /* AG control information */
+};
 
 /*
  *     In-core inode map control page
index 5a558ce..ab0566f 100644 (file)
  */
 struct jfs_superblock {
        char s_magic[4];        /* 4: magic number */
-       u32 s_version;          /* 4: version number */
+       __le32 s_version;       /* 4: version number */
 
-       s64 s_size;             /* 8: aggregate size in hardware/LVM blocks;
+       __le64 s_size;          /* 8: aggregate size in hardware/LVM blocks;
                                 * VFS: number of blocks
                                 */
-       s32 s_bsize;            /* 4: aggregate block size in bytes; 
+       __le32 s_bsize;         /* 4: aggregate block size in bytes; 
                                 * VFS: fragment size
                                 */
-       s16 s_l2bsize;          /* 2: log2 of s_bsize */
-       s16 s_l2bfactor;        /* 2: log2(s_bsize/hardware block size) */
-       s32 s_pbsize;           /* 4: hardware/LVM block size in bytes */
-       s16 s_l2pbsize;         /* 2: log2 of s_pbsize */
-       s16 pad;                /* 2: padding necessary for alignment */
+       __le16 s_l2bsize;       /* 2: log2 of s_bsize */
+       __le16 s_l2bfactor;     /* 2: log2(s_bsize/hardware block size) */
+       __le32 s_pbsize;        /* 4: hardware/LVM block size in bytes */
+       __le16 s_l2pbsize;      /* 2: log2 of s_pbsize */
+       __le16 pad;             /* 2: padding necessary for alignment */
 
-       u32 s_agsize;           /* 4: allocation group size in aggr. blocks */
+       __le32 s_agsize;        /* 4: allocation group size in aggr. blocks */
 
-       u32 s_flag;             /* 4: aggregate attributes:
+       __le32 s_flag;          /* 4: aggregate attributes:
                                 *    see jfs_filsys.h
                                 */
-       u32 s_state;            /* 4: mount/unmount/recovery state: 
+       __le32 s_state;         /* 4: mount/unmount/recovery state: 
                                 *    see jfs_filsys.h
                                 */
-       s32 s_compress;         /* 4: > 0 if data compression */
+       __le32 s_compress;              /* 4: > 0 if data compression */
 
        pxd_t s_ait2;           /* 8: first extent of secondary
                                 *    aggregate inode table
@@ -66,15 +66,15 @@ struct jfs_superblock {
        pxd_t s_aim2;           /* 8: first extent of secondary
                                 *    aggregate inode map
                                 */
-       u32 s_logdev;           /* 4: device address of log */
-       s32 s_logserial;        /* 4: log serial number at aggregate mount */
+       __le32 s_logdev;                /* 4: device address of log */
+       __le32 s_logserial;     /* 4: log serial number at aggregate mount */
        pxd_t s_logpxd;         /* 8: inline log extent */
 
        pxd_t s_fsckpxd;        /* 8: inline fsck work space extent */
 
        struct timestruc_t s_time;      /* 8: time last updated */
 
-       s32 s_fsckloglen;       /* 4: Number of filesystem blocks reserved for
+       __le32 s_fsckloglen;    /* 4: Number of filesystem blocks reserved for
                                 *    the fsck service log.  
                                 *    N.B. These blocks are divided among the
                                 *         versions kept.  This is not a per
@@ -95,7 +95,7 @@ struct jfs_superblock {
                                 */
 
        /* extendfs() parameter under s_state & FM_EXTENDFS */
-       s64 s_xsize;            /* 8: extendfs s_size */
+       __le64 s_xsize;         /* 8: extendfs s_size */
        pxd_t s_xfsckpxd;       /* 8: extendfs fsckpxd */
        pxd_t s_xlogpxd;        /* 8: extendfs logpxd */
        /* - 128 byte boundary - */
index 974077f..b32208a 100644 (file)
@@ -29,7 +29,7 @@
  * FUNCTION:   Convert little-endian unicode string to character string
  *
  */
-int jfs_strfromUCS_le(char *to, const wchar_t * from,  /* LITTLE ENDIAN */
+int jfs_strfromUCS_le(char *to, const __le16 * from,
                      int len, struct nls_table *codepage)
 {
        int i;
index af6ccd2..69e25eb 100644 (file)
@@ -31,7 +31,7 @@ typedef struct {
 extern signed char UniUpperTable[512];
 extern UNICASERANGE UniUpperRange[];
 extern int get_UCSname(struct component_name *, struct dentry *);
-extern int jfs_strfromUCS_le(char *, const wchar_t *, int, struct nls_table *);
+extern int jfs_strfromUCS_le(char *, const __le16 *, int, struct nls_table *);
 
 #define free_UCSname(COMP) kfree((COMP)->name)
 
@@ -51,10 +51,10 @@ static inline wchar_t *UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
 /*
  * UniStrncpy:  Copy length limited string with pad
  */
-static inline wchar_t *UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2,
+static inline __le16 *UniStrncpy_le(__le16 * ucs1, const __le16 * ucs2,
                                  size_t n)
 {
-       wchar_t *anchor = ucs1;
+       __le16 *anchor = ucs1;
 
        while (n-- && *ucs2)    /* Copy the strings */
                *ucs1++ = *ucs2++;
@@ -68,7 +68,7 @@ static inline wchar_t *UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2,
 /*
  * UniStrncmp_le:  Compare length limited string - native to little-endian
  */
-static inline int UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2,
+static inline int UniStrncmp_le(const wchar_t * ucs1, const __le16 * ucs2,
                                size_t n)
 {
        if (!n)
@@ -81,10 +81,27 @@ static inline int UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2,
 }
 
 /*
- * UniStrncpy_le:  Copy length limited string with pad to little-endian
+ * UniStrncpy_to_le:  Copy length limited string with pad to little-endian
+ */
+static inline __le16 *UniStrncpy_to_le(__le16 * ucs1, const wchar_t * ucs2,
+                                      size_t n)
+{
+       __le16 *anchor = ucs1;
+
+       while (n-- && *ucs2)    /* Copy the strings */
+               *ucs1++ = cpu_to_le16(*ucs2++);
+
+       n++;
+       while (n--)             /* Pad with nulls */
+               *ucs1++ = 0;
+       return anchor;
+}
+
+/*
+ * UniStrncpy_from_le:  Copy length limited string with pad from little-endian
  */
-static inline wchar_t *UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2,
-                                    size_t n)
+static inline wchar_t *UniStrncpy_from_le(wchar_t * ucs1, const __le16 * ucs2,
+                                         size_t n)
 {
        wchar_t *anchor = ucs1;
 
@@ -97,7 +114,6 @@ static inline wchar_t *UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2,
        return anchor;
 }
 
-
 /*
  * UniToupper:  Convert a unicode character to upper case
  */
index acc196e..a1052f3 100644 (file)
 struct jfs_ea {
        u8 flag;        /* Unused? */
        u8 namelen;     /* Length of name */
-       u16 valuelen;   /* Length of value */
+       __le16 valuelen;        /* Length of value */
        char name[0];   /* Attribute name (includes null-terminator) */
 };                     /* Value immediately follows name */
 
 struct jfs_ea_list {
-       u32 size;               /* overall size */
+       __le32 size;            /* overall size */
        struct jfs_ea ea[0];    /* Variable length list */
 };
 
index 7ae64d5..a697842 100644 (file)
@@ -32,10 +32,10 @@ typedef struct xad {
        unsigned flag:8;        /* 1: flag */
        unsigned rsvrd:16;      /* 2: reserved */
        unsigned off1:8;        /* 1: offset in unit of fsblksize */
-       u32 off2;               /* 4: offset in unit of fsblksize */
+       __le32 off2;            /* 4: offset in unit of fsblksize */
        unsigned len:24;        /* 3: length in unit of fsblksize */
        unsigned addr1:8;       /* 1: address in unit of fsblksize */
-       u32 addr2;              /* 4: address in unit of fsblksize */
+       __le32 addr2;           /* 4: address in unit of fsblksize */
 } xad_t;                       /* (16) */
 
 #define MAXXLEN         ((1 << 24) - 1)
@@ -90,14 +90,14 @@ struct xadlist {
  */
 typedef union {
        struct xtheader {
-               s64 next;       /* 8: */
-               s64 prev;       /* 8: */
+               __le64 next;    /* 8: */
+               __le64 prev;    /* 8: */
 
                u8 flag;        /* 1: */
                u8 rsrvd1;      /* 1: */
-               s16 nextindex;  /* 2: next index = number of entries */
-               s16 maxentry;   /* 2: max number of entries */
-               s16 rsrvd2;     /* 2: */
+               __le16 nextindex;       /* 2: next index = number of entries */
+               __le16 maxentry;        /* 2: max number of entries */
+               __le16 rsrvd2;  /* 2: */
 
                pxd_t self;     /* 8: self */
        } header;               /* (32) */
index 5d3f82b..fe8d6e2 100644 (file)
@@ -391,13 +391,9 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files
                return -ENOMEM;
        }
        for (i = 0; !files->name || files->name[0]; i++, files++) {
-               struct qstr name;
                if (!files->name)
                        continue;
-               name.name = files->name;
-               name.len = strlen(name.name);
-               name.hash = full_name_hash(name.name, name.len);
-               dentry = d_alloc(root, &name);
+               dentry = d_alloc_name(root, files->name);
                if (!dentry)
                        goto out;
                inode = new_inode(s);
@@ -530,6 +526,7 @@ EXPORT_SYMBOL(simple_commit_write);
 EXPORT_SYMBOL(simple_dir_inode_operations);
 EXPORT_SYMBOL(simple_dir_operations);
 EXPORT_SYMBOL(simple_empty);
+EXPORT_SYMBOL(d_alloc_name);
 EXPORT_SYMBOL(simple_fill_super);
 EXPORT_SYMBOL(simple_getattr);
 EXPORT_SYMBOL(simple_link);
index 571af5b..7725a0a 100644 (file)
@@ -5,6 +5,6 @@
 obj-$(CONFIG_LOCKD) += lockd.o
 
 lockd-objs-y := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
-               svcproc.o svcsubs.o mon.o xdr.o lockd_syms.o
+               svcproc.o svcsubs.o mon.o xdr.o
 lockd-objs-$(CONFIG_LOCKD_V4) += xdr4.o svc4proc.o
 lockd-objs                   := $(lockd-objs-y)
index daae633..36bc602 100644 (file)
@@ -14,7 +14,7 @@
 #include "minix.h"
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 
 static int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
 
@@ -160,7 +160,8 @@ minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
 
 static void minix_clear_inode(struct inode *inode)
 {
-       struct buffer_head *bh;
+       struct buffer_head *bh = NULL;
+
        if (INODE_VERSION(inode) == MINIX_V1) {
                struct minix_inode *raw_inode;
                raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -188,24 +189,26 @@ void minix_free_inode(struct inode * inode)
        struct buffer_head * bh;
        unsigned long ino;
 
-       if (inode->i_ino < 1 || inode->i_ino > sbi->s_ninodes) {
-               printk("free_inode: inode 0 or nonexistent inode\n");
-               return;
-       }
        ino = inode->i_ino;
+       if (ino < 1 || ino > sbi->s_ninodes) {
+               printk("minix_free_inode: inode 0 or nonexistent inode\n");
+               goto out;
+       }
        if ((ino >> 13) >= sbi->s_imap_blocks) {
-               printk("free_inode: nonexistent imap in superblock\n");
-               return;
+               printk("minix_free_inode: nonexistent imap in superblock\n");
+               goto out;
        }
 
+       minix_clear_inode(inode);       /* clear on-disk copy */
+
        bh = sbi->s_imap[ino >> 13];
-       minix_clear_inode(inode);
-       clear_inode(inode);
        lock_kernel();
        if (!minix_test_and_clear_bit(ino & 8191, bh->b_data))
-               printk("free_inode: bit %lu already cleared.\n",ino);
+               printk("minix_free_inode: bit %lu already cleared.\n", ino);
        unlock_kernel();
        mark_buffer_dirty(bh);
+ out:
+       clear_inode(inode);             /* clear in-memory copy */
 }
 
 struct inode * minix_new_inode(const struct inode * dir, int * error)
index 817f57a..50be17d 100644 (file)
@@ -501,8 +501,8 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
                mark_inode_dirty(new_inode);
        }
        if (dotdot_bh) {
-               dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
-               dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
+               dotdot_de->start = cpu_to_le16(MSDOS_I(new_dir)->i_logstart);
+               dotdot_de->starthi = cpu_to_le16((MSDOS_I(new_dir)->i_logstart) >> 16);
                mark_buffer_dirty(dotdot_bh);
                old_dir->i_nlink--;
                mark_inode_dirty(old_dir);
index 8a06919..fe03e31 100644 (file)
@@ -180,7 +180,6 @@ nfsd(struct svc_rqst *rqstp)
        /* Lock module and set up kernel thread */
        lock_kernel();
        daemonize("nfsd");
-       current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
 
        /* After daemonize() this kernel thread shares current->fs
         * with the init process. We need to create files with a
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 */
index b8f0611..12cf2e3 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "bitmap.h"
 #include "debug.h"
+#include "aops.h"
 #include "ntfs.h"
 
 /**
index b19a488..71bd2cd 100644 (file)
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include "ntfs.h"
+#include "aops.h"
 #include "collate.h"
+#include "debug.h"
 #include "index.h"
+#include "ntfs.h"
 
 /**
  * ntfs_index_ctx_get - allocate and initialize a new index context
@@ -261,7 +263,6 @@ done:
                ntfs_error(sb, "No index allocation attribute but index entry "
                                "requires one.  Inode 0x%lx is corrupt or "
                                "driver bug.", idx_ni->mft_no);
-               err = -EIO;
                goto err_out;
        }
        /* Get the starting vcn of the index_block holding the child node. */
@@ -299,7 +300,13 @@ fast_descend_into_child_node:
        if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
                ntfs_error(sb, "Out of bounds check failed.  Corrupt inode "
                                "0x%lx or driver bug.", idx_ni->mft_no);
-               err = -EIO;
+               goto unm_err_out;
+       }
+       /* Catch multi sector transfer fixup errors. */
+       if (unlikely(!ntfs_is_indx_record(ia->magic))) {
+               ntfs_error(sb, "Index record with vcn 0x%llx is corrupt.  "
+                               "Corrupt inode 0x%lx.  Run chkdsk.",
+                               (long long)vcn, idx_ni->mft_no);
                goto unm_err_out;
        }
        if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
@@ -309,7 +316,6 @@ fast_descend_into_child_node:
                                (unsigned long long)
                                sle64_to_cpu(ia->index_block_vcn),
                                (unsigned long long)vcn, idx_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
@@ -321,7 +327,6 @@ fast_descend_into_child_node:
                                idx_ni->mft_no,
                                le32_to_cpu(ia->index.allocated_size) + 0x18,
                                idx_ni->itype.index.block_size);
-               err = -EIO;
                goto unm_err_out;
        }
        index_end = (u8*)ia + idx_ni->itype.index.block_size;
@@ -331,7 +336,6 @@ fast_descend_into_child_node:
                                "access!  This is probably a bug in the "
                                "driver.", (unsigned long long)vcn,
                                idx_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
@@ -339,7 +343,6 @@ fast_descend_into_child_node:
                ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of inode "
                                "0x%lx exceeds maximum size.",
                                (unsigned long long)vcn, idx_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        /* The first index entry. */
@@ -357,11 +360,10 @@ fast_descend_into_child_node:
                                (u8*)ie + le16_to_cpu(ie->length) > index_end) {
                        ntfs_error(sb, "Index entry out of bounds in inode "
                                        "0x%lx.", idx_ni->mft_no);
-                       err = -EIO;
                        goto unm_err_out;
                }
                /*
-                * The last entry cannot contain a ket.  It can however contain
+                * The last entry cannot contain a key.  It can however contain
                 * a pointer to a child node in the B+tree so we just break out.
                 */
                if (ie->flags & INDEX_ENTRY_END)
@@ -375,7 +377,6 @@ fast_descend_into_child_node:
                                le16_to_cpu(ie->length)) {
                        ntfs_error(sb, "Index entry out of bounds in inode "
                                        "0x%lx.", idx_ni->mft_no);
-                       err = -EIO;
                        goto unm_err_out;
                }
                /* If the keys match perfectly, we setup @ictx and return 0. */
@@ -422,7 +423,6 @@ ia_done:
        if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
                ntfs_error(sb, "Index entry with child node found in a leaf "
                                "node in inode 0x%lx.", idx_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        /* Child node present, descend into it. */
@@ -444,11 +444,12 @@ ia_done:
        }
        ntfs_error(sb, "Negative child node vcn in inode 0x%lx.",
                        idx_ni->mft_no);
-       err = -EIO;
 unm_err_out:
        unlock_page(page);
        ntfs_unmap_page(page);
 err_out:
+       if (!err)
+               err = -EIO;
        if (actx)
                ntfs_attr_put_search_ctx(actx);
        if (m)
@@ -456,61 +457,5 @@ err_out:
        return err;
 idx_err_out:
        ntfs_error(sb, "Corrupt index.  Aborting lookup.");
-       err = -EIO;
        goto err_out;
 }
-
-#ifdef NTFS_RW
-
-/**
- * __ntfs_index_entry_mark_dirty - mark an index allocation entry dirty
- * @ictx:      ntfs index context describing the index entry
- *
- * NOTE: You want to use fs/ntfs/index.h::ntfs_index_entry_mark_dirty() instead!
- * 
- * Mark the index allocation entry described by the index entry context @ictx
- * dirty.
- *
- * The index entry must be in an index block belonging to the index allocation
- * attribute.  Mark the buffers belonging to the index record as well as the
- * page cache page the index block is in dirty.  This automatically marks the
- * VFS inode of the ntfs index inode to which the index entry belongs dirty,
- * too (I_DIRTY_PAGES) and this in turn ensures the page buffers, and hence the
- * dirty index block, will be written out to disk later.
- */
-void __ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
-{
-       ntfs_inode *ni;
-       struct page *page;
-       struct buffer_head *bh, *head;
-       unsigned int rec_start, rec_end, bh_size, bh_start, bh_end;
-
-       BUG_ON(ictx->is_in_root);
-       ni = ictx->idx_ni;
-       page = ictx->page;
-       BUG_ON(!page_has_buffers(page));
-       /*
-        * If the index block is the same size as the page cache page, set all
-        * the buffers in the page, as well as the page itself, dirty.
-        */
-       if (ni->itype.index.block_size == PAGE_CACHE_SIZE) {
-               __set_page_dirty_buffers(page);
-               return;
-       }
-       /* Set only the buffers in which the index block is located dirty. */
-       rec_start = (unsigned int)((u8*)ictx->ia - (u8*)page_address(page));
-       rec_end = rec_start + ni->itype.index.block_size;
-       bh_size = ni->vol->sb->s_blocksize;
-       bh_start = 0;
-       bh = head = page_buffers(page);
-       do {
-               bh_end = bh_start + bh_size;
-               if ((bh_start >= rec_start) && (bh_end <= rec_end))
-                       set_buffer_dirty(bh);
-               bh_start = bh_end;
-       } while ((bh = bh->b_this_page) != head);
-       /* Finally, set the page itself dirty, too. */
-       __set_page_dirty_nobuffers(page);
-}
-
-#endif /* NTFS_RW */
index 159442d..846a489 100644 (file)
@@ -30,6 +30,7 @@
 #include "inode.h"
 #include "attrib.h"
 #include "mft.h"
+#include "aops.h"
 
 /**
  * @idx_ni:    index inode containing the @entry described by this context
@@ -115,8 +116,6 @@ static inline void ntfs_index_entry_flush_dcache_page(ntfs_index_context *ictx)
                flush_dcache_page(ictx->page);
 }
 
-extern void __ntfs_index_entry_mark_dirty(ntfs_index_context *ictx);
-
 /**
  * ntfs_index_entry_mark_dirty - mark an index entry dirty
  * @ictx:      ntfs index context describing the index entry
@@ -140,7 +139,8 @@ static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
        if (ictx->is_in_root)
                mark_mft_record_dirty(ictx->actx->ntfs_ino);
        else
-               __ntfs_index_entry_mark_dirty(ictx);
+               mark_ntfs_record_dirty(ictx->page,
+                               (u8*)ictx->ia - (u8*)page_address(ictx->page));
 }
 
 #endif /* NTFS_RW */
index 748ed0d..23fd911 100644 (file)
@@ -30,6 +30,7 @@
 #include "volume.h"
 #include "attrib.h"
 #include "malloc.h"
+#include "aops.h"
 #include "ntfs.h"
 
 /**
@@ -46,7 +47,7 @@
  * 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,
+int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
                const runlist_element *rl)
 {
        struct inode *lcnbmp_vi = vol->lcnbmp_ino;
@@ -855,7 +856,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
                err = PTR_ERR(rl);
                goto err_out;
        }
-       if (unlikely(rl->lcn < (LCN)LCN_HOLE)) {
+       if (unlikely(rl->lcn < LCN_HOLE)) {
                if (!is_rollback)
                        ntfs_error(vol->sb, "First runlist element has "
                                        "invalid lcn, aborting.");
@@ -895,15 +896,15 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
         * free them.
         */
        for (; rl->length && count != 0; ++rl) {
-               if (unlikely(rl->lcn < (LCN)LCN_HOLE)) {
+               if (unlikely(rl->lcn < LCN_HOLE)) {
                        VCN vcn;
 
                        /*
                         * Attempt to map runlist, dropping runlist lock for
                         * the duration.
                         */
-                       up_read(&ni->runlist.lock);
                        vcn = rl->vcn;
+                       up_read(&ni->runlist.lock);
                        err = ntfs_map_runlist(ni, vcn);
                        if (err) {
                                if (!is_rollback)
@@ -926,7 +927,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
                                                        "element.");
                                goto err_out;
                        }
-                       if (unlikely(rl->lcn < (LCN)LCN_HOLE)) {
+                       if (unlikely(rl->lcn < LCN_HOLE)) {
                                if (!is_rollback)
                                        ntfs_error(vol->sb, "Runlist element "
                                                        "has invalid lcn "
index f9292e8..4cac1c0 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/fs.h>
 
 #include "types.h"
+#include "runlist.h"
 #include "volume.h"
 
 typedef enum {
@@ -78,6 +79,34 @@ static inline s64 ntfs_cluster_free(struct inode *vi, const VCN start_vcn,
        return __ntfs_cluster_free(vi, start_vcn, count, FALSE);
 }
 
+extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
+               const runlist_element *rl);
+
+/**
+ * ntfs_cluster_free_from_rl - 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: This function takes the volume lcn bitmap lock for writing and
+ *         modifies the bitmap contents.
+ */
+static inline int ntfs_cluster_free_from_rl(ntfs_volume *vol,
+               const runlist_element *rl)
+{
+       int ret;
+
+       down_write(&vol->lcnbmp_lock);
+       ret = ntfs_cluster_free_from_rl_nolock(vol, rl);
+       up_write(&vol->lcnbmp_lock);
+       return ret;
+}
+
 #endif /* NTFS_RW */
 
 #endif /* defined _LINUX_NTFS_LCNALLOC_H */
index b72a85d..833df2a 100644 (file)
 
 #ifdef NTFS_RW
 
-#include "ntfs.h"
 #include "index.h"
 #include "quota.h"
+#include "debug.h"
+#include "ntfs.h"
 
 /**
  * ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume
@@ -51,7 +52,7 @@ BOOL ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
        ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino));
        if (!ictx) {
                ntfs_error(vol->sb, "Failed to get index context.");
-               return FALSE;
+               goto err_out;
        }
        err = ntfs_index_lookup(&qid, sizeof(qid), ictx);
        if (err) {
@@ -107,7 +108,8 @@ done:
        ntfs_debug("Done.");
        return TRUE;
 err_out:
-       ntfs_index_ctx_put(ictx);
+       if (ictx)
+               ntfs_index_ctx_put(ictx);
        up(&vol->quota_q_ino->i_sem);
        return FALSE;
 }
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 */
index 9b4d037..87f5044 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/genhd.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/semaphore.h>
 
 
index 4cb2960..0f5b017 100644 (file)
@@ -3,7 +3,7 @@
  * Per Intel EFI Specification v1.02
  * http://developer.intel.com/technology/efi/efi.htm
  * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
- *   Copyright 2000,2001,2002 Dell Inc.
+ *   Copyright 2000,2001,2002,2004 Dell 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
  * TODO:
  *
  * Changelog:
+ * Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com>
+ * - test for valid PMBR and valid PGPT before ever reading
+ *   AGPT, allow override with 'gpt' kernel command line option.
+ * - check for first/last_usable_lba outside of size of disk
+ *
  * Tue  Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com>
  * - Ported to 2.5.7-pre1 and 2.5.7-dj2
  * - Applied patch to avoid fault in alternate header handling
@@ -130,32 +135,6 @@ efi_crc32(const void *buf, unsigned long len)
        return (crc32(~0L, buf, len) ^ ~0L);
 }
 
-/**
- * is_pmbr_valid(): test Protective MBR for validity
- * @mbr: pointer to a legacy mbr structure
- *
- * Description: Returns 1 if PMBR is valid, 0 otherwise.
- * Validity depends on two things:
- *  1) MSDOS signature is in the last two bytes of the MBR
- *  2) One partition of type 0xEE is found
- */
-static int
-is_pmbr_valid(legacy_mbr *mbr)
-{
-       int i, found = 0, signature = 0;
-       if (!mbr)
-               return 0;
-       signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
-       for (i = 0; signature && i < 4; i++) {
-               if (mbr->partition_record[i].sys_ind ==
-                    EFI_PMBR_OSTYPE_EFI_GPT) {
-                       found = 1;
-                       break;
-               }
-       }
-       return (signature && found);
-}
-
 /**
  * last_lba(): return number of last logical block of device
  * @bdev: block device
@@ -168,7 +147,40 @@ is_pmbr_valid(legacy_mbr *mbr)
 static u64
 last_lba(struct block_device *bdev)
 {
-       return (bdev->bd_inode->i_size >> 9) - 1;
+       if (!bdev || !bdev->bd_inode)
+               return 0;
+       return (bdev->bd_inode->i_size >> 9) - 1ULL;
+}
+
+static inline int
+pmbr_part_valid(struct partition *part, u64 lastlba)
+{
+        if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
+            le32_to_cpu(part->start_sect) == 1UL)
+                return 1;
+        return 0;
+}
+
+/**
+ * is_pmbr_valid(): test Protective MBR for validity
+ * @mbr: pointer to a legacy mbr structure
+ * @lastlba: last_lba for the whole device
+ *
+ * Description: Returns 1 if PMBR is valid, 0 otherwise.
+ * Validity depends on two things:
+ *  1) MSDOS signature is in the last two bytes of the MBR
+ *  2) One partition of type 0xEE is found
+ */
+static int
+is_pmbr_valid(legacy_mbr *mbr, u64 lastlba)
+{
+       int i;
+       if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
+                return 0;
+       for (i = 0; i < 4; i++)
+               if (pmbr_part_valid(&mbr->partition_record[i], lastlba))
+                        return 1;
+       return 0;
 }
 
 /**
@@ -186,8 +198,8 @@ read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count)
 {
        size_t totalreadcount = 0;
 
-       if (!bdev || !buffer)
-               return 0;
+       if (!bdev || !buffer || lba > last_lba(bdev))
+                return 0;
 
        while (count) {
                int copied = 512;
@@ -206,7 +218,6 @@ read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count)
        return totalreadcount;
 }
 
-
 /**
  * alloc_read_gpt_entries(): reads partition entries from disk
  * @bdev
@@ -289,6 +300,7 @@ is_gpt_valid(struct block_device *bdev, u64 lba,
             gpt_header **gpt, gpt_entry **ptes)
 {
        u32 crc, origcrc;
+       u64 lastlba;
 
        if (!bdev || !gpt || !ptes)
                return 0;
@@ -301,9 +313,7 @@ is_gpt_valid(struct block_device *bdev, u64 lba,
                        "%lld != %lld\n",
                        (unsigned long long)le64_to_cpu((*gpt)->signature),
                        (unsigned long long)GPT_HEADER_SIGNATURE);
-               kfree(*gpt);
-               *gpt = NULL;
-               return 0;
+               goto fail;
        }
 
        /* Check the GUID Partition Table CRC */
@@ -315,9 +325,7 @@ is_gpt_valid(struct block_device *bdev, u64 lba,
                Dprintk
                    ("GUID Partition Table Header CRC is wrong: %x != %x\n",
                     crc, origcrc);
-               kfree(*gpt);
-               *gpt = NULL;
-               return 0;
+               goto fail;
        }
        (*gpt)->header_crc32 = cpu_to_le32(origcrc);
 
@@ -327,16 +335,28 @@ is_gpt_valid(struct block_device *bdev, u64 lba,
                Dprintk("GPT my_lba incorrect: %lld != %lld\n",
                        (unsigned long long)le64_to_cpu((*gpt)->my_lba),
                        (unsigned long long)lba);
-               kfree(*gpt);
-               *gpt = NULL;
-               return 0;
+               goto fail;
        }
 
-       if (!(*ptes = alloc_read_gpt_entries(bdev, *gpt))) {
-               kfree(*gpt);
-               *gpt = NULL;
-               return 0;
+       /* Check the first_usable_lba and last_usable_lba are
+        * within the disk.
+        */
+       lastlba = last_lba(bdev);
+       if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
+               Dprintk("GPT: first_usable_lba incorrect: %lld > %lld\n",
+                       (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba),
+                       (unsigned long long)lastlba);
+               goto fail;
        }
+       if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) {
+               Dprintk("GPT: last_usable_lba incorrect: %lld > %lld\n",
+                       (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
+                       (unsigned long long)lastlba);
+               goto fail;
+       }
+
+       if (!(*ptes = alloc_read_gpt_entries(bdev, *gpt)))
+               goto fail;
 
        /* Check the GUID Partition Entry Array CRC */
        crc = efi_crc32((const unsigned char *) (*ptes),
@@ -345,15 +365,36 @@ is_gpt_valid(struct block_device *bdev, u64 lba,
 
        if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
                Dprintk("GUID Partitition Entry Array CRC check failed.\n");
-               kfree(*gpt);
-               *gpt = NULL;
-               kfree(*ptes);
-               *ptes = NULL;
-               return 0;
+               goto fail_ptes;
        }
 
        /* We're done, all's well */
        return 1;
+
+ fail_ptes:
+       kfree(*ptes);
+       *ptes = NULL;
+ fail:
+       kfree(*gpt);
+       *gpt = NULL;
+       return 0;
+}
+
+/**
+ * is_pte_valid() - tests one PTE for validity
+ * @pte is the pte to check
+ * @lastlba is last lba of the disk
+ *
+ * Description: returns 1 if valid,  0 on error.
+ */
+static inline int
+is_pte_valid(const gpt_entry *pte, const u64 lastlba)
+{
+       if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
+           le64_to_cpu(pte->starting_lba) > lastlba         ||
+           le64_to_cpu(pte->ending_lba)   > lastlba)
+               return 0;
+       return 1;
 }
 
 /**
@@ -464,8 +505,13 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
  * @ptes is a PTEs ptr, filled on return.
  * Description: Returns 1 if valid, 0 on error.
  * If valid, returns pointers to newly allocated GPT header and PTEs.
- * Validity depends on finding either the Primary GPT header and PTEs valid,
- * or the Alternate GPT header and PTEs valid, and the PMBR valid.
+ * Validity depends on PMBR being valid (or being overridden by the
+ * 'gpt' kernel command line option) and finding either the Primary
+ * GPT header and PTEs valid, or the Alternate GPT header and PTEs
+ * valid.  If the Primary GPT header is not valid, the Alternate GPT header
+ * is not checked unless the 'gpt' kernel command line option is passed.
+ * This protects against devices which misreport their size, and forces
+ * the user to decide to use the Alternate GPT.
  */
 static int
 find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
@@ -479,70 +525,43 @@ find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
                return 0;
 
        lastlba = last_lba(bdev);
+        if (!force_gpt) {
+                /* This will be added to the EFI Spec. per Intel after v1.02. */
+                legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
+                if (legacymbr) {
+                        memset(legacymbr, 0, sizeof (*legacymbr));
+                        read_lba(bdev, 0, (u8 *) legacymbr,
+                                 sizeof (*legacymbr));
+                        good_pmbr = is_pmbr_valid(legacymbr, lastlba);
+                        kfree(legacymbr);
+                        legacymbr=NULL;
+                }
+                if (!good_pmbr)
+                        goto fail;
+        }
+
        good_pgpt = is_gpt_valid(bdev, GPT_PRIMARY_PARTITION_TABLE_LBA,
                                 &pgpt, &pptes);
-        if (good_pgpt) {
+        if (good_pgpt)
                good_agpt = is_gpt_valid(bdev,
-                                         le64_to_cpu(pgpt->alternate_lba),
+                                        le64_to_cpu(pgpt->alternate_lba),
                                         &agpt, &aptes);
-                if (!good_agpt) {
-                        good_agpt = is_gpt_valid(bdev, lastlba,
-                                                 &agpt, &aptes);
-                }
-        }
-        else {
+        if (!good_agpt && force_gpt)
                 good_agpt = is_gpt_valid(bdev, lastlba,
                                          &agpt, &aptes);
-        }
 
         /* The obviously unsuccessful case */
-        if (!good_pgpt && !good_agpt) {
-                goto fail;
-        }
-
-       /* This will be added to the EFI Spec. per Intel after v1.02. */
-        legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
-        if (legacymbr) {
-                memset(legacymbr, 0, sizeof (*legacymbr));
-                read_lba(bdev, 0, (u8 *) legacymbr,
-                         sizeof (*legacymbr));
-                good_pmbr = is_pmbr_valid(legacymbr);
-                kfree(legacymbr);
-                legacymbr=NULL;
-        }
-
-        /* Failure due to bad PMBR */
-        if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
-                printk(KERN_WARNING 
-                       "  Warning: Disk has a valid GPT signature "
-                       "but invalid PMBR.\n");
-                printk(KERN_WARNING
-                       "  Assuming this disk is *not* a GPT disk anymore.\n");
-                printk(KERN_WARNING
-                       "  Use gpt kernel option to override.  "
-                       "Use GNU Parted to correct disk.\n");
+        if (!good_pgpt && !good_agpt)
                 goto fail;
-        }
-
-        /* Would fail due to bad PMBR, but force GPT anyhow */
-        if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
-                printk(KERN_WARNING
-                       "  Warning: Disk has a valid GPT signature but "
-                       "invalid PMBR.\n");
-                printk(KERN_WARNING
-                       "  Use GNU Parted to correct disk.\n");
-                printk(KERN_WARNING
-                       "  gpt option taken, disk treated as GPT.\n");
-        }
 
         compare_gpts(pgpt, agpt, lastlba);
 
         /* The good cases */
-        if (good_pgpt && (good_pmbr || force_gpt)) {
+        if (good_pgpt) {
                 *gpt  = pgpt;
                 *ptes = pptes;
-                if (agpt)  { kfree(agpt);   agpt = NULL; }
-                if (aptes) { kfree(aptes); aptes = NULL; }
+                kfree(agpt);
+                kfree(aptes);
                 if (!good_agpt) {
                         printk(KERN_WARNING 
                               "Alternate GPT is invalid, "
@@ -550,21 +569,21 @@ find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
                 }
                 return 1;
         }
-        else if (good_agpt && (good_pmbr || force_gpt)) {
+        else if (good_agpt) {
                 *gpt  = agpt;
                 *ptes = aptes;
-                if (pgpt)  { kfree(pgpt);   pgpt = NULL; }
-                if (pptes) { kfree(pptes); pptes = NULL; }
+                kfree(pgpt);
+                kfree(pptes);
                 printk(KERN_WARNING 
                        "Primary GPT is invalid, using alternate GPT.\n");
                 return 1;
         }
 
  fail:
-        if (pgpt)  { kfree(pgpt);   pgpt=NULL; }
-        if (agpt)  { kfree(agpt);   agpt=NULL; }
-        if (pptes) { kfree(pptes); pptes=NULL; }
-        if (aptes) { kfree(aptes); aptes=NULL; }
+        kfree(pgpt);
+        kfree(agpt);
+        kfree(pptes);
+        kfree(aptes);
         *gpt = NULL;
         *ptes = NULL;
         return 0;
@@ -606,15 +625,15 @@ efi_partition(struct parsed_partitions *state, struct block_device *bdev)
        Dprintk("GUID Partition Table is valid!  Yea!\n");
 
        for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
-               if (!efi_guidcmp(ptes[i].partition_type_guid, NULL_GUID))
+               if (!is_pte_valid(&ptes[i], last_lba(bdev)))
                        continue;
 
                put_partition(state, i+1, le64_to_cpu(ptes[i].starting_lba),
                                 (le64_to_cpu(ptes[i].ending_lba) -
                                   le64_to_cpu(ptes[i].starting_lba) +
-                                 1));
+                                 1ULL));
 
-               /* If there's this is a RAID volume, tell md */
+               /* If this is a RAID volume, tell md */
                if (!efi_guidcmp(ptes[i].partition_type_guid,
                                 PARTITION_LINUX_RAID_GUID))
                        state->parts[i+1].flags = 1;
@@ -624,22 +643,3 @@ efi_partition(struct parsed_partitions *state, struct block_device *bdev)
        printk("\n");
        return 1;
 }
-
-/*
- * 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-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
index 7232785..ea634dc 100644 (file)
@@ -21,8 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/buffer_head.h>
-
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 
 int qnx4_new_block(struct super_block *sb)
 {
index c569276..1700120 100644 (file)
 
 int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
 {
+        int err = 0;
        struct reiserfs_super_block * sb;
         struct reiserfs_bitmap_info *bitmap;
+       struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
        struct buffer_head * bh;
        struct reiserfs_transaction_handle th;
        unsigned int bmap_nr_new, bmap_nr;
@@ -107,12 +109,19 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
             * block pointers */
            bitmap = vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
            if (!bitmap) {
+               /* Journal bitmaps are still supersized, but the memory isn't
+                * leaked, so I guess it's ok */
                printk("reiserfs_resize: unable to allocate memory.\n");
                return -ENOMEM;
            }
            memset (bitmap, 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
            for (i = 0; i < bmap_nr; i++)
-               bitmap[i] = SB_AP_BITMAP(s)[i];
+               bitmap[i] = old_bitmap[i];
+
+           /* This doesn't go through the journal, but it doesn't have to.
+            * The changes are still atomic: We're synced up when the journal
+            * transaction begins, and the new bitmaps don't matter if the
+            * transaction fails. */
            for (i = bmap_nr; i < bmap_nr_new; i++) {
                bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
                memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
@@ -126,12 +135,16 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
                bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
            }   
            /* free old bitmap blocks array */
-           vfree(SB_AP_BITMAP(s));
            SB_AP_BITMAP(s) = bitmap;
+           vfree (old_bitmap);
        }
        
-       /* begin transaction */
-       journal_begin(&th, s, 10);
+       /* begin transaction, if there was an error, it's fine. Yes, we have
+        * incorrect bitmaps now, but none of it is ever going to touch the
+        * disk anyway. */
+       err = journal_begin(&th, s, 10);
+       if (err)
+           return err;
 
        /* correct last bitmap blocks in old and new disk layout */
        reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
@@ -165,8 +178,5 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
        journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
        
        SB_JOURNAL(s)->j_must_wait = 1;
-       journal_end(&th, s, 10);
-
-       return 0;
+       return journal_end(&th, s, 10);
 }
-
index 3cbcd7b..66ea6e9 100644 (file)
@@ -19,7 +19,7 @@ Wed, 4 Feb 1998   Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
        *    namei.c: removed static subdir(); is_subdir() from dcache.c
                      is used instead. Cosmetic changes.
 
-Thu, 3 Dec 1998   Al Viro (viro@math.psu.edu)
+Thu, 3 Dec 1998   Al Viro (viro@parcelfarce.linux.theplanet.co.uk)
        *    namei.c (sysv_rmdir):
                      Bugectomy: old check for victim being busy
                      (inode->i_count) wasn't replaced (with checking
index 19abd51..18e3487 100644 (file)
@@ -4,7 +4,7 @@ Thu Feb 14 2002  Andrew Morton  <akpm@zip.com.au>
          waitfor_one_page() for IS_SYNC directories, so that we
          actually do sync the directory. (forward-port from 2.4).
 
-Thu Feb  7 2002  Alexander Viro  <viro@math.psu.edu>
+Thu Feb  7 2002  Alexander Viro  <viro@parcelfarce.linux.theplanet.co.uk>
 
        * super.c: switched to ->get_sb()
        * ChangeLog: fixed dates ;-)
@@ -13,7 +13,7 @@ Thu Feb  7 2002  Alexander Viro  <viro@math.psu.edu>
 
        * inode.c: Include linux/init.h
 
-Mon Jan 21 2002  Alexander Viro  <viro@math.psu.edu>
+Mon Jan 21 2002  Alexander Viro  <viro@parcelfarce.linux.theplanet.co.uk>
        * ialloc.c (sysv_new_inode): zero SYSV_I(inode)->i_data out.
        * i_vnode renamed to vfs_inode.  Sorry, but let's keep that
          consistent.
@@ -43,7 +43,7 @@ Sat Jan 19 2002  Christoph Hellwig  <hch@infradead.org>
        * symlink.c (sysv_readlink): Likewise.
        (sysv_follow_link): Likewise.
 
-Fri Jan  4 2002  Alexander Viro  <viro@math.psu.edu>
+Fri Jan  4 2002  Alexander Viro  <viro@parcelfarce.linux.theplanet.co.uk>
 
        * ialloc.c (sysv_free_inode): Use sb->s_id instead of bdevname().
        * inode.c (sysv_read_inode): Likewise.
@@ -59,16 +59,16 @@ Sun Dec 30 2001  Manfred Spraul  <manfreds@colorfullife.com>
        * dir.c (dir_commit_chunk): Do not set dir->i_version.
        (sysv_readdir): Likewise.
 
-Thu Dec 27 2001  Alexander Viro  <viro@math.psu.edu>
+Thu Dec 27 2001  Alexander Viro  <viro@parcelfarce.linux.theplanet.co.uk>
 
        * itree.c (get_block): Use map_bh() to fill out bh_result.
 
-Tue Dec 25 2001  Alexander Viro  <viro@math.psu.edu>
+Tue Dec 25 2001  Alexander Viro  <viro@parcelfarce.linux.theplanet.co.uk>
 
        * super.c (sysv_read_super): Use sb_set_blocksize() to set blocksize.
          (v7_read_super): Likewise.
 
-Tue Nov 27 2001  Alexander Viro  <viro@math.psu.edu>
+Tue Nov 27 2001  Alexander Viro  <viro@parcelfarce.linux.theplanet.co.uk>
 
        * itree.c (get_block): Change type for iblock argument to sector_t.
        * super.c (sysv_read_super): Set s_blocksize early.
index 235418f..cddb733 100644 (file)
@@ -28,7 +28,7 @@
 
 #include <linux/quotaops.h>
 #include <linux/buffer_head.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 
 #include "udf_i.h"
 #include "udf_sb.h"
index 33640a9..2faa417 100644 (file)
@@ -254,30 +254,10 @@ static int udf_release_file(struct inode * inode, struct file * filp)
        return 0;
 }
 
-/*
- * udf_open_file
- *
- * PURPOSE
- *  Called when an inode is about to be open.
- *
- * DESCRIPTION
- *  Use this to disallow opening RW large files on 32 bit systems.
- *  On 64 bit systems we force on O_LARGEFILE in sys_open.
- *
- * HISTORY
- *
- */
-static int udf_open_file(struct inode * inode, struct file * filp)
-{
-       if ((inode->i_size & 0xFFFFFFFF80000000ULL) && !(filp->f_flags & O_LARGEFILE))
-               return -EFBIG;
-       return 0;
-}
-
 struct file_operations udf_file_operations = {
        .read                   = generic_file_read,
        .ioctl                  = udf_ioctl,
-       .open                   = udf_open_file,
+       .open                   = generic_file_open,
        .mmap                   = generic_file_mmap,
        .write                  = udf_file_write,
        .release                = udf_release_file,
index f7d1557..2da5087 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/cdrom.h>
 #include <asm/uaccess.h>
-#include <scsi/scsi.h>
-
-typedef struct scsi_device Scsi_Device;
-typedef struct scsi_cmnd   Scsi_Cmnd;
-
-#include <scsi/scsi_ioctl.h>
 
 #include <linux/udf_fs.h>
 #include "udf_sb.h"
index 105a695..14abb8b 100644 (file)
@@ -13,8 +13,8 @@
 #include <linux/time.h>
 #include <linux/stat.h>
 #include <linux/string.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/byteorder.h>
 
 #include "swab.h"
index 767cb8f..ed6e546 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/byteorder.h>
 
 #include "swab.h"
index 2e8d466..42b0944 100644 (file)
@@ -629,7 +629,7 @@ void ufs_read_inode (struct inode * inode)
                }
        } else
                init_special_inode(inode, inode->i_mode,
-                       old_decode_dev(fs32_to_cpu(sb, ufsi->i_u1.i_data[0])));
+                       ufs_get_inode_dev(sb, ufsi));
 
        brelse (bh);
 
@@ -705,7 +705,7 @@ ufs2_inode :
                }
        } else   /* TODO  : here ...*/
                init_special_inode(inode, inode->i_mode,
-                       old_decode_dev(fs32_to_cpu(sb, ufsi->i_u1.i_data[0])));
+                       ufs_get_inode_dev(sb, ufsi));
 
        brelse(bh);
 
index 2fbba03..421a78a 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include "swab.h"      /* will go away - see comment in mknod() */
+#include "util.h"
 
 /*
 #undef UFS_NAMEI_DEBUG
@@ -125,8 +126,7 @@ static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t
        if (!IS_ERR(inode)) {
                init_special_inode(inode, mode, rdev);
                /* NOTE: that'll go when we get wide dev_t */
-               UFS_I(inode)->i_u1.i_data[0] = cpu_to_fs32(inode->i_sb,
-                                                       old_encode_dev(rdev));
+               ufs_set_inode_dev(inode->i_sb, UFS_I(inode), rdev);
                mark_inode_dirty(inode);
                lock_kernel();
                err = ufs_add_nondir(dentry, inode);
index 4ff38a0..7bcd4fc 100644 (file)
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 
 #include <stdarg.h>
 
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
index 8072875..59acc8f 100644 (file)
@@ -202,3 +202,56 @@ void _ubh_memcpyubh_(struct ufs_sb_private_info * uspi,
                bhno++;
        }
 }
+
+dev_t
+ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi)
+{
+       __fs32 fs32;
+       dev_t dev;
+
+       if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
+               fs32 = ufsi->i_u1.i_data[1];
+       else
+               fs32 = ufsi->i_u1.i_data[0];
+       fs32 = fs32_to_cpu(sb, fs32);
+       switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
+       case UFS_ST_SUNx86:
+       case UFS_ST_SUN:
+               if ((fs32 & 0xffff0000) == 0 ||
+                   (fs32 & 0xffff0000) == 0xffff0000)
+                       dev = old_decode_dev(fs32 & 0x7fff);
+               else
+                       dev = MKDEV(sysv_major(fs32), sysv_minor(fs32));
+               break;
+
+       default:
+               dev = old_decode_dev(fs32);
+               break;
+       }
+       return dev;
+}
+
+void
+ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev)
+{
+       __fs32 fs32;
+
+       switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
+       case UFS_ST_SUNx86:
+       case UFS_ST_SUN:
+               fs32 = sysv_encode_dev(dev);
+               if ((fs32 & 0xffff8000) == 0) {
+                       fs32 = old_encode_dev(dev);
+               }
+               break;
+
+       default:
+               fs32 = old_encode_dev(dev);
+               break;
+       }
+       fs32 = cpu_to_fs32(sb, fs32);
+       if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
+               ufsi->i_u1.i_data[1] = fs32;
+       else
+               ufsi->i_u1.i_data[0] = fs32;
+}
index 58770d2..b264007 100644 (file)
@@ -223,6 +223,8 @@ ufs_set_inode_gid(struct super_block *sb, struct ufs_inode *inode, u32 value)
        inode->ui_u1.oldids.ui_sgid =  cpu_to_fs16(sb, value);
 }
 
+extern dev_t ufs_get_inode_dev(struct super_block *, struct ufs_inode_info *);
+extern void ufs_set_inode_dev(struct super_block *, struct ufs_inode_info *, dev_t);
 
 /*
  * These functions manipulate ufs buffers
index fae7176..364ea8c 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
 #include <linux/swap.h>
+#include <linux/blkdev.h>
 
 #include "time.h"
 #include "kmem.h"
@@ -46,7 +47,8 @@
 void *
 kmem_alloc(size_t size, int flags)
 {
-       int     retries = 0, lflags = kmem_flags_convert(flags);
+       int     retries = 0;
+       int     lflags = kmem_flags_convert(flags);
        void    *ptr;
 
        do {
@@ -57,8 +59,10 @@ kmem_alloc(size_t size, int flags)
                if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
                        return ptr;
                if (!(++retries % 100))
-                       printk(KERN_ERR "possible deadlock in %s (mode:0x%x)\n",
+                       printk(KERN_ERR "XFS: possible memory allocation "
+                                       "deadlock in %s (mode:0x%x)\n",
                                        __FUNCTION__, lflags);
+               blk_congestion_wait(WRITE, HZ/50);
        } while (1);
 }
 
@@ -102,7 +106,8 @@ kmem_realloc(void *ptr, size_t newsize, size_t oldsize, int flags)
 void *
 kmem_zone_alloc(kmem_zone_t *zone, int flags)
 {
-       int     retries = 0, lflags = kmem_flags_convert(flags);
+       int     retries = 0;
+       int     lflags = kmem_flags_convert(flags);
        void    *ptr;
 
        do {
@@ -110,8 +115,10 @@ kmem_zone_alloc(kmem_zone_t *zone, int flags)
                if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
                        return ptr;
                if (!(++retries % 100))
-                       printk(KERN_ERR "possible deadlock in %s (mode:0x%x)\n",
+                       printk(KERN_ERR "XFS: possible memory allocation "
+                                       "deadlock in %s (mode:0x%x)\n",
                                        __FUNCTION__, lflags);
+               blk_congestion_wait(WRITE, HZ/50);
        } while (1);
 }
 
index ffe383e..14d594a 100644 (file)
@@ -83,7 +83,7 @@ typedef unsigned long xfs_pflags_t;
 
 static __inline unsigned int kmem_flags_convert(int flags)
 {
-       int lflags;
+       int     lflags = __GFP_NOWARN;  /* we'll report problems, if need be */
 
 #ifdef DEBUG
        if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL))) {
index 4c0a72c..4f7b9d3 100644 (file)
 #include <linux/workqueue.h>
 #include <linux/suspend.h>
 #include <linux/percpu.h>
+#include <linux/blkdev.h>
 
 #include "xfs_linux.h"
 
-#ifndef GFP_READAHEAD
-#define GFP_READAHEAD  (__GFP_NOWARN|__GFP_NORETRY)
-#endif
-
 /*
  * File wide globals
  */
@@ -118,8 +115,8 @@ ktrace_t *pagebuf_trace_buf;
  */
 
 #define pb_to_gfp(flags) \
-       (((flags) & PBF_READ_AHEAD) ? GFP_READAHEAD : \
-        ((flags) & PBF_DONT_BLOCK) ? GFP_NOFS : GFP_KERNEL)
+       ((((flags) & PBF_READ_AHEAD) ? __GFP_NORETRY : \
+         ((flags) & PBF_DONT_BLOCK) ? GFP_NOFS : GFP_KERNEL) | __GFP_NOWARN)
 
 #define pb_to_km(flags) \
         (((flags) & PBF_DONT_BLOCK) ? KM_NOFS : KM_SLEEP)
@@ -387,13 +384,13 @@ _pagebuf_lookup_pages(
                         */
                        if (!(++retries % 100))
                                printk(KERN_ERR
-                                       "possible deadlock in %s (mode:0x%x)\n",
+                                       "XFS: possible memory allocation "
+                                       "deadlock in %s (mode:0x%x)\n",
                                        __FUNCTION__, gfp_mask);
 
                        XFS_STATS_INC(pb_page_retries);
                        pagebuf_daemon_wakeup(0, gfp_mask);
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(10);
+                       blk_congestion_wait(WRITE, HZ/50);
                        goto retry;
                }
 
@@ -486,7 +483,7 @@ _pagebuf_map_pages(
  *     which may imply that this call will block until those buffers
  *     are unlocked.  No I/O is implied by this call.
  */
-STATIC xfs_buf_t *
+xfs_buf_t *
 _pagebuf_find(                         /* find buffer for block        */
        xfs_buftarg_t           *target,/* target for block             */
        loff_t                  ioff,   /* starting offset of range     */
@@ -578,39 +575,14 @@ found:
        return (pb);
 }
 
-
 /*
- *     pagebuf_find
+ *     xfs_buf_get_flags assembles a buffer covering the specified range.
  *
- *     pagebuf_find returns a buffer matching the specified range of
- *     data for the specified target, if any of the relevant blocks
- *     are in memory.  The buffer may have unallocated holes, if
- *     some, but not all, of the blocks are in memory.  Even where
- *     pages are present in the buffer, not all of every page may be
- *     valid.
+ *     Storage in memory for all portions of the buffer will be allocated,
+ *     although backing storage may not be.
  */
 xfs_buf_t *
-pagebuf_find(                          /* find buffer for block        */
-                                       /* if the block is in memory    */
-       xfs_buftarg_t           *target,/* target for block             */
-       loff_t                  ioff,   /* starting offset of range     */
-       size_t                  isize,  /* length of range              */
-       page_buf_flags_t        flags)  /* PBF_TRYLOCK                  */
-{
-       return _pagebuf_find(target, ioff, isize, flags, NULL);
-}
-
-/*
- *     pagebuf_get
- *
- *     pagebuf_get assembles a buffer covering the specified range.
- *     Some or all of the blocks in the range may be valid.  Storage
- *     in memory for all portions of the buffer will be allocated,
- *     although backing storage may not be.  If PBF_READ is set in
- *     flags, pagebuf_iostart is called also.
- */
-xfs_buf_t *
-pagebuf_get(                           /* allocate a buffer            */
+xfs_buf_get_flags(                     /* allocate a buffer            */
        xfs_buftarg_t           *target,/* target for buffer            */
        loff_t                  ioff,   /* starting offset of range     */
        size_t                  isize,  /* length of range              */
@@ -640,8 +612,8 @@ pagebuf_get(                                /* allocate a buffer            */
        if (!(pb->pb_flags & PBF_MAPPED)) {
                error = _pagebuf_map_pages(pb, flags);
                if (unlikely(error)) {
-                       printk(KERN_WARNING
-                              "pagebuf_get: failed to map pages\n");
+                       printk(KERN_WARNING "%s: failed to map pages\n",
+                                       __FUNCTION__);
                        goto no_buffer;
                }
        }
@@ -655,30 +627,50 @@ pagebuf_get(                              /* allocate a buffer            */
        pb->pb_bn = ioff;
        pb->pb_count_desired = pb->pb_buffer_length;
 
-       if (flags & PBF_READ) {
+       PB_TRACE(pb, "get", (unsigned long)flags);
+       return pb;
+
+ no_buffer:
+       if (flags & (PBF_LOCK | PBF_TRYLOCK))
+               pagebuf_unlock(pb);
+       pagebuf_rele(pb);
+       return NULL;
+}
+
+xfs_buf_t *
+xfs_buf_read_flags(
+       xfs_buftarg_t           *target,
+       loff_t                  ioff,
+       size_t                  isize,
+       page_buf_flags_t        flags)
+{
+       xfs_buf_t               *pb;
+
+       flags |= PBF_READ;
+
+       pb = xfs_buf_get_flags(target, ioff, isize, flags);
+       if (pb) {
                if (PBF_NOT_DONE(pb)) {
-                       PB_TRACE(pb, "get_read", (unsigned long)flags);
+                       PB_TRACE(pb, "read", (unsigned long)flags);
                        XFS_STATS_INC(pb_get_read);
                        pagebuf_iostart(pb, flags);
                } else if (flags & PBF_ASYNC) {
-                       PB_TRACE(pb, "get_read_async", (unsigned long)flags);
+                       PB_TRACE(pb, "read_async", (unsigned long)flags);
                        /*
                         * Read ahead call which is already satisfied,
                         * drop the buffer
                         */
                        goto no_buffer;
                } else {
-                       PB_TRACE(pb, "get_read_done", (unsigned long)flags);
+                       PB_TRACE(pb, "read_done", (unsigned long)flags);
                        /* We do not want read in the flags */
                        pb->pb_flags &= ~PBF_READ;
                }
-       } else {
-               PB_TRACE(pb, "get_write", (unsigned long)flags);
        }
 
        return pb;
 
-no_buffer:
+ no_buffer:
        if (flags & (PBF_LOCK | PBF_TRYLOCK))
                pagebuf_unlock(pb);
        pagebuf_rele(pb);
@@ -723,8 +715,8 @@ pagebuf_readahead(
        if (bdi_write_congested(bdi))
                return;
 
-       flags |= (PBF_TRYLOCK|PBF_READ|PBF_ASYNC|PBF_READ_AHEAD);
-       pagebuf_get(target, ioff, isize, flags);
+       flags |= (PBF_TRYLOCK|PBF_ASYNC|PBF_READ_AHEAD);
+       xfs_buf_read_flags(target, ioff, isize, flags);
 }
 
 xfs_buf_t *
@@ -1084,7 +1076,7 @@ _pagebuf_wait_unpin(
  *     done with respect to that I/O.  The pb_iodone routine, if
  *     present, will be called as a side-effect.
  */
-void
+STATIC void
 pagebuf_iodone_work(
        void                    *v)
 {
@@ -1263,7 +1255,7 @@ bio_end_io_pagebuf(
        return 0;
 }
 
-void
+STATIC void
 _pagebuf_ioapply(
        xfs_buf_t               *pb)
 {
@@ -1473,6 +1465,34 @@ pagebuf_iomove(
  *     Handling of buftargs.
  */
 
+/*
+ * Wait for any bufs with callbacks that have been submitted but
+ * have not yet returned... walk the hash list for the target.
+ */
+void
+xfs_wait_buftarg(
+       xfs_buftarg_t *target)
+{
+       xfs_buf_t       *pb, *n;
+       pb_hash_t       *h;
+       int             i;
+
+       for (i = 0; i < NHASH; i++) {
+               h = &pbhash[i];
+again:
+               spin_lock(&h->pb_hash_lock);
+               list_for_each_entry_safe(pb, n, &h->pb_hash, pb_hash_list) {
+                       if (pb->pb_target == target &&
+                                       !(pb->pb_flags & PBF_FS_MANAGED)) {
+                               spin_unlock(&h->pb_hash_lock);
+                               delay(100);
+                               goto again;
+                       }
+               }
+               spin_unlock(&h->pb_hash_lock);
+       }
+}
+
 void
 xfs_free_buftarg(
        xfs_buftarg_t           *btp,
index 242ba07..dc43517 100644 (file)
@@ -168,20 +168,36 @@ typedef struct xfs_buf {
 
 /* Finding and Reading Buffers */
 
-extern xfs_buf_t *pagebuf_find(        /* find buffer for block if     */
+extern xfs_buf_t *_pagebuf_find(       /* find buffer for block if     */
                                        /* the block is in memory       */
                xfs_buftarg_t *,        /* inode for block              */
                loff_t,                 /* starting offset of range     */
                size_t,                 /* length of range              */
-               page_buf_flags_t);      /* PBF_LOCK                     */
+               page_buf_flags_t,       /* PBF_LOCK                     */
+               xfs_buf_t *);           /* newly allocated buffer       */
 
-extern xfs_buf_t *pagebuf_get(         /* allocate a buffer            */
+#define xfs_incore(buftarg,blkno,len,lockit) \
+       _pagebuf_find(buftarg, blkno ,len, lockit, NULL)
+
+extern xfs_buf_t *xfs_buf_get_flags(   /* allocate a buffer            */
                xfs_buftarg_t *,        /* inode for buffer             */
                loff_t,                 /* starting offset of range     */
                size_t,                 /* length of range              */
                page_buf_flags_t);      /* PBF_LOCK, PBF_READ,          */
                                        /* PBF_ASYNC                    */
 
+#define xfs_buf_get(target, blkno, len, flags) \
+       xfs_buf_get_flags((target), (blkno), (len), PBF_LOCK | PBF_MAPPED)
+
+extern xfs_buf_t *xfs_buf_read_flags(  /* allocate and read a buffer   */
+               xfs_buftarg_t *,        /* inode for buffer             */
+               loff_t,                 /* starting offset of range     */
+               size_t,                 /* length of range              */
+               page_buf_flags_t);      /* PBF_LOCK, PBF_ASYNC          */
+
+#define xfs_buf_read(target, blkno, len, flags) \
+       xfs_buf_read_flags((target), (blkno), (len), PBF_LOCK | PBF_MAPPED)
+
 extern xfs_buf_t *pagebuf_lookup(
                xfs_buftarg_t *,
                loff_t,                 /* starting offset of range     */
@@ -472,18 +488,6 @@ extern inline xfs_caddr_t xfs_buf_offset(xfs_buf_t *bp, size_t offset)
 #define XFS_BUF_SET_VTYPE(bp, type)
 #define XFS_BUF_SET_REF(bp, ref)
 
-#define xfs_buf_read(target, blkno, len, flags) \
-               pagebuf_get((target), (blkno), (len), \
-                       PBF_LOCK | PBF_READ | PBF_MAPPED)
-#define xfs_buf_get(target, blkno, len, flags) \
-               pagebuf_get((target), (blkno), (len), \
-                       PBF_LOCK | PBF_MAPPED)
-
-#define xfs_buf_read_flags(target, blkno, len, flags) \
-               pagebuf_get((target), (blkno), (len), PBF_READ | (flags))
-#define xfs_buf_get_flags(target, blkno, len, flags) \
-               pagebuf_get((target), (blkno), (len), (flags))
-
 static inline int      xfs_bawrite(void *mp, xfs_buf_t *bp)
 {
        bp->pb_fspriv3 = mp;
@@ -508,10 +512,6 @@ static inline void xfs_buf_relse(xfs_buf_t *bp)
 #define xfs_biodone(pb)                    \
            pagebuf_iodone(pb, (pb->pb_flags & PBF_FS_DATAIOD), 0)
 
-#define xfs_incore(buftarg,blkno,len,lockit) \
-           pagebuf_find(buftarg, blkno ,len, lockit)
-
-
 #define xfs_biomove(pb, off, len, data, rw) \
            pagebuf_iomove((pb), (off), (len), (data), \
                ((rw) == XFS_B_WRITE) ? PBRW_WRITE : PBRW_READ)
@@ -566,6 +566,7 @@ static inline int xfs_bdwrite(void *mp, xfs_buf_t *bp)
 
 extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *);
 extern void xfs_free_buftarg(xfs_buftarg_t *, int);
+extern void xfs_wait_buftarg(xfs_buftarg_t *);
 extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
 extern void xfs_incore_relse(xfs_buftarg_t *, int, int);
 extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
index 910d5bc..66462e1 100644 (file)
@@ -398,7 +398,7 @@ linvfs_file_mmap(
        vattr_t         va = { .va_mask = XFS_AT_UPDATIME };
        int             error;
 
-       if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
+       if (vp->v_vfsp->vfs_flag & VFS_DMI) {
                xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
 
                error = -XFS_SEND_MMAP(mp, vma, 0);
@@ -473,7 +473,7 @@ linvfs_mprotect(
        vnode_t         *vp = LINVFS_GET_VP(vma->vm_file->f_dentry->d_inode);
        int             error = 0;
 
-       if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
+       if (vp->v_vfsp->vfs_flag & VFS_DMI) {
                if ((vma->vm_flags & VM_MAYSHARE) &&
                    (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE)) {
                        xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
index b9c4bbf..a6da5b4 100644 (file)
@@ -64,6 +64,7 @@ xfs_param_t xfs_params = {
        .xfs_buf_timer  = {     100/2,          1*100,          30*100  },
        .xfs_buf_age    = {     1*100,          15*100,         7200*100},
        .inherit_nosym  = {     0,              0,              1       },
+       .rotorstep      = {     1,              1,              255     },
 };
 
 /*
index bbf4ef4..5c05be6 100644 (file)
@@ -142,6 +142,7 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh)
 #define xfs_buf_timer_centisecs        xfs_params.xfs_buf_timer.val
 #define xfs_buf_age_centisecs  xfs_params.xfs_buf_age.val
 #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val
+#define xfs_rotorstep          xfs_params.rotorstep.val
 
 #define current_cpu()          smp_processor_id()
 #define current_pid()          (current->pid)
index 903e60e..88e2b7c 100644 (file)
@@ -244,6 +244,7 @@ xfs_read(
        cred_t                  *credp)
 {
        struct file             *file = iocb->ki_filp;
+       struct inode            *inode = file->f_mapping->host;
        size_t                  size = 0;
        ssize_t                 ret;
        xfs_fsize_t             n;
@@ -272,7 +273,7 @@ xfs_read(
        }
        /* END copy & waste from filemap.c */
 
-       if (ioflags & IO_ISDIRECT) {
+       if (unlikely(ioflags & IO_ISDIRECT)) {
                xfs_buftarg_t   *target =
                        (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
                                mp->m_rtdev_targp : mp->m_ddev_targp;
@@ -296,18 +297,20 @@ xfs_read(
                return -EIO;
        }
 
+       if (unlikely(ioflags & IO_ISDIRECT))
+               down(&inode->i_sem);
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
 
        if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
            !(ioflags & IO_INVIS)) {
                vrwlock_t locktype = VRWLOCK_READ;
 
-               ret = XFS_SEND_DATA(mp, DM_EVENT_READ,
+               ret = -XFS_SEND_DATA(mp, DM_EVENT_READ,
                                        BHV_TO_VNODE(bdp), *offset, size,
                                        FILP_DELAY_FLAG(file), &locktype);
                if (ret) {
                        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-                       return -ret;
+                       goto unlock_isem;
                }
        }
 
@@ -316,15 +319,17 @@ xfs_read(
        ret = __generic_file_aio_read(iocb, iovp, segs, offset);
        if (ret == -EIOCBQUEUED)
                ret = wait_on_sync_kiocb(iocb);
-
-       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-
        if (ret > 0)
                XFS_STATS_ADD(xs_read_bytes, ret);
 
+       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+
        if (likely(!(ioflags & IO_INVIS)))
                xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
 
+unlock_isem:
+       if (unlikely(ioflags & IO_ISDIRECT))
+               up(&inode->i_sem);
        return ret;
 }
 
index c245296..0dc0103 100644 (file)
@@ -134,6 +134,11 @@ STATIC ctl_table xfs_table[] = {
        &sysctl_intvec, NULL,
        &xfs_params.inherit_nosym.min, &xfs_params.inherit_nosym.max},
 
+       {XFS_ROTORSTEP, "rotorstep", &xfs_params.rotorstep.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL, 
+       &xfs_params.rotorstep.min, &xfs_params.rotorstep.max},
+
        /* please keep this the last entry */
 #ifdef CONFIG_PROC_FS
        {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val,
index 5ff61bb..a39a950 100644 (file)
@@ -60,6 +60,7 @@ typedef struct xfs_param {
        xfs_sysctl_val_t xfs_buf_timer; /* Interval between xfsbufd wakeups. */
        xfs_sysctl_val_t xfs_buf_age;   /* Metadata buffer age before flush. */
        xfs_sysctl_val_t inherit_nosym; /* Inherit the "nosymlinks" flag. */
+       xfs_sysctl_val_t rotorstep;     /* inode32 AG rotoring control knob */
 } xfs_param_t;
 
 /*
@@ -97,6 +98,7 @@ enum {
        XFS_BUF_AGE = 17,
        /* XFS_IO_BYPASS = 18 */
        XFS_INHERIT_NOSYM = 19,
+       XFS_ROTORSTEP = 20,
 };
 
 extern xfs_param_t     xfs_params;
index f539e92..dcf1a7a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-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
@@ -182,10 +182,13 @@ typedef struct xfs_dquot_acct {
 #define XFS_QM_HOLD(xqm)       ((xqm)->qm_nrefs++)
 #define XFS_QM_RELE(xqm)       ((xqm)->qm_nrefs--)
 
+extern void            xfs_mount_reset_sbqflags(xfs_mount_t *);
+
 extern int             xfs_qm_init_quotainfo(xfs_mount_t *);
 extern void            xfs_qm_destroy_quotainfo(xfs_mount_t *);
-extern int             xfs_qm_mount_quotas(xfs_mount_t *);
+extern int             xfs_qm_mount_quotas(xfs_mount_t *, int);
 extern void            xfs_qm_mount_quotainit(xfs_mount_t *, uint);
+extern int             xfs_qm_quotacheck(xfs_mount_t *);
 extern void            xfs_qm_unmount_quotadestroy(xfs_mount_t *);
 extern int             xfs_qm_unmount_quotas(xfs_mount_t *);
 extern int             xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
index 96b1d58..be67d9c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-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
@@ -207,10 +207,9 @@ xfs_qm_syncall(
 }
 
 /*
- * When xfsquotas isn't installed and the superblock had quotas, we need to
- * clear the quotaflags from superblock.
+ * Clear the quotaflags in memory and in the superblock.
  */
-STATIC void
+void
 xfs_mount_reset_sbqflags(
        xfs_mount_t             *mp)
 {
@@ -241,6 +240,8 @@ xfs_mount_reset_sbqflags(
        if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
                                      XFS_DEFAULT_LOG_COUNT)) {
                xfs_trans_cancel(tp, 0);
+               xfs_fs_cmn_err(CE_ALERT, mp,
+                       "xfs_mount_reset_sbqflags: Superblock update failed!");
                return;
        }
        xfs_mod_sb(tp, XFS_SB_QFLAGS);
@@ -294,15 +295,12 @@ xfs_qm_newmount(
                 */
                if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
                        /*
-                        * If the xfs quota code isn't installed,
-                        * we have to reset the quotachk'd bit.
                         * If an error occured, qm_mount_quotas code
                         * has already disabled quotas. So, just finish
                         * mounting, and get on with the boring life
                         * without disk quotas.
                         */
-                       if (xfs_qm_mount_quotas(mp))
-                               xfs_mount_reset_sbqflags(mp);
+                       xfs_qm_mount_quotas(mp, 0);
                } else {
                        /*
                         * Clear the quota flags, but remember them. This
@@ -324,13 +322,13 @@ STATIC int
 xfs_qm_endmount(
        xfs_mount_t     *mp,
        uint            needquotamount,
-       uint            quotaflags)
+       uint            quotaflags,
+       int             mfsi_flags)
 {
        if (needquotamount) {
                ASSERT(mp->m_qflags == 0);
                mp->m_qflags = quotaflags;
-               if (xfs_qm_mount_quotas(mp))
-                       xfs_mount_reset_sbqflags(mp);
+               xfs_qm_mount_quotas(mp, mfsi_flags);
        }
 
 #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
index 02337c2..fa8799d 100644 (file)
@@ -2247,6 +2247,7 @@ xfs_alloc_vextent(
        xfs_alloctype_t type;   /* input allocation type */
        int             bump_rotor = 0;
        int             no_min = 0;
+       xfs_agnumber_t  rotorstep = xfs_rotorstep; /* inode32 agf stepper */
 
        mp = args->mp;
        type = args->otype = args->type;
@@ -2310,7 +2311,9 @@ xfs_alloc_vextent(
                 */
                if ((args->userdata  == XFS_ALLOC_INITIAL_USER_DATA) &&
                    (mp->m_flags & XFS_MOUNT_32BITINODES)) {
-                       args->fsbno = XFS_AGB_TO_FSB(mp, mp->m_agfrotor, 0);
+                       args->fsbno = XFS_AGB_TO_FSB(mp,
+                                       ((mp->m_agfrotor / rotorstep) %
+                                       mp->m_sb.sb_agcount), 0);
                        bump_rotor = 1;
                }
                args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
@@ -2326,7 +2329,8 @@ xfs_alloc_vextent(
                        /*
                         * Start with the last place we left off.
                         */
-                       args->agno = sagno = mp->m_agfrotor;
+                       args->agno = sagno = (mp->m_agfrotor / rotorstep) %
+                                       mp->m_sb.sb_agcount;
                        args->type = XFS_ALLOCTYPE_THIS_AG;
                        flags = XFS_ALLOC_FLAG_TRYLOCK;
                } else if (type == XFS_ALLOCTYPE_FIRST_AG) {
@@ -2400,8 +2404,14 @@ xfs_alloc_vextent(
                        }
                }
                up_read(&mp->m_peraglock);
-               if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG))
-                       mp->m_agfrotor = (args->agno + 1) % mp->m_sb.sb_agcount;
+               if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) {
+                       if (args->agno == sagno)
+                               mp->m_agfrotor = (mp->m_agfrotor + 1) %
+                                       (mp->m_sb.sb_agcount * rotorstep);
+                       else
+                               mp->m_agfrotor = (args->agno * rotorstep + 1) %
+                                       (mp->m_sb.sb_agcount * rotorstep);
+               }
                break;
        default:
                ASSERT(0);
index 07641fc..bef9164 100644 (file)
@@ -169,6 +169,7 @@ xfs_iget_core(
        xfs_mount_t     *mp,
        xfs_trans_t     *tp,
        xfs_ino_t       ino,
+       uint            flags,
        uint            lock_flags,
        xfs_inode_t     **ipp,
        xfs_daddr_t     bno)
@@ -180,7 +181,6 @@ xfs_iget_core(
        ulong           version;
        int             error;
        /* REFERENCED */
-       int             newnode;
        xfs_chash_t     *ch;
        xfs_chashlist_t *chl, *chlnew;
        SPLDECL(s);
@@ -193,11 +193,22 @@ again:
 
        for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) {
                if (ip->i_ino == ino) {
+                       /*
+                        * If INEW is set this inode is being set up
+                        * we need to pause and try again.
+                        */
+                       if (ip->i_flags & XFS_INEW) {
+                               read_unlock(&ih->ih_lock);
+                               delay(1);
+                               XFS_STATS_INC(xs_ig_frecycle);
 
-                       inode_vp = XFS_ITOV_NULL(ip);
+                               goto again;
+                       }
 
+                       inode_vp = XFS_ITOV_NULL(ip);
                        if (inode_vp == NULL) {
-                               /* If IRECLAIM is set this inode is
+                               /*
+                                * If IRECLAIM is set this inode is
                                 * on its way out of the system,
                                 * we need to pause and try again.
                                 */
@@ -250,14 +261,15 @@ again:
                        XFS_STATS_INC(xs_ig_found);
 
 finish_inode:
-                       if (lock_flags != 0) {
-                               xfs_ilock(ip, lock_flags);
-                       }
-
-                       newnode = (ip->i_d.di_mode == 0);
-                       if (newnode) {
+                       if (ip->i_d.di_mode == 0) {
+                               if (!(flags & IGET_CREATE))
+                                       return ENOENT;
                                xfs_iocore_inode_reinit(ip);
                        }
+       
+                       if (lock_flags != 0)
+                               xfs_ilock(ip, lock_flags);
+
                        ip->i_flags &= ~XFS_ISTALE;
 
                        vn_trace_exit(vp, "xfs_iget.found",
@@ -293,6 +305,11 @@ finish_inode:
        if (lock_flags != 0) {
                xfs_ilock(ip, lock_flags);
        }
+               
+       if ((ip->i_d.di_mode == 0) && !(flags & IGET_CREATE)) {
+               xfs_idestroy(ip);
+               return ENOENT;
+       }
 
        /*
         * Put ip on its hash chain, unless someone else hashed a duplicate
@@ -324,6 +341,7 @@ finish_inode:
        ih->ih_next = ip;
        ip->i_udquot = ip->i_gdquot = NULL;
        ih->ih_version++;
+       ip->i_flags |= XFS_INEW;
 
        write_unlock(&ih->ih_lock);
 
@@ -404,8 +422,6 @@ finish_inode:
 
        XFS_MOUNT_IUNLOCK(mp);
 
-       newnode = 1;
-
  return_ip:
        ASSERT(ip->i_df.if_ext_max ==
               XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
@@ -434,6 +450,7 @@ xfs_iget(
        xfs_mount_t     *mp,
        xfs_trans_t     *tp,
        xfs_ino_t       ino,
+       uint            flags,
        uint            lock_flags,
        xfs_inode_t     **ipp,
        xfs_daddr_t     bno)
@@ -454,8 +471,8 @@ retry:
                if (inode->i_state & I_NEW) {
 inode_allocate:
                        vn_initialize(inode);
-                       error = xfs_iget_core(vp, mp, tp, ino,
-                                               lock_flags, ipp, bno);
+                       error = xfs_iget_core(vp, mp, tp, ino, flags,
+                                       lock_flags, ipp, bno);
                        if (error) {
                                vn_mark_bad(vp);
                                if (inode->i_state & I_NEW)
@@ -576,6 +593,10 @@ xfs_iput_new(xfs_inode_t   *ip,
 
        vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address);
 
+       if ((ip->i_d.di_mode == 0)) {
+               ASSERT(!(ip->i_flags & XFS_IRECLAIMABLE));
+               vn_mark_bad(vp);
+       }
        if (inode->i_state & I_NEW)
                unlock_new_inode(inode);
        if (lock_flags)
index 7d91f70..0505a30 100644 (file)
@@ -430,7 +430,6 @@ typedef struct xlog_iclog_fields {
        int                     ic_size;
        int                     ic_offset;
        int                     ic_refcnt;
-       int                     ic_roundoff;
        int                     ic_bwritecnt;
        ushort_t                ic_state;
        char                    *ic_datap;      /* pointer to iclog data */
@@ -462,7 +461,6 @@ typedef struct xlog_in_core {
 #define        ic_size         hic_fields.ic_size
 #define        ic_offset       hic_fields.ic_offset
 #define        ic_refcnt       hic_fields.ic_refcnt
-#define        ic_roundoff     hic_fields.ic_roundoff
 #define        ic_bwritecnt    hic_fields.ic_bwritecnt
 #define        ic_state        hic_fields.ic_state
 #define ic_datap       hic_fields.ic_datap
@@ -498,7 +496,6 @@ typedef struct log {
        xfs_daddr_t             l_logBBstart;   /* start block of log */
        int                     l_logsize;      /* size of log in bytes */
        int                     l_logBBsize;    /* size of log in BB chunks */
-       int                     l_roundoff;     /* round off error of iclogs */
        int                     l_curr_cycle;   /* Cycle number of log writes */
        int                     l_prev_cycle;   /* Cycle number before last
                                                 * block increment */
@@ -545,7 +542,7 @@ extern int   xlog_find_tail(xlog_t  *log,
                                int readonly);
 extern int      xlog_recover(xlog_t *log, int readonly);
 extern int      xlog_recover_finish(xlog_t *log, int mfsi_flags);
-extern void     xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog);
+extern void     xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int);
 extern void     xlog_recover_process_iunlinks(xlog_t *log);
 
 extern struct xfs_buf *xlog_get_bp(xlog_t *, int);
index c2f55e0..e2c3706 100644 (file)
@@ -95,6 +95,7 @@ xfs_trans_iget(
        xfs_mount_t     *mp,
        xfs_trans_t     *tp,
        xfs_ino_t       ino,
+       uint            flags,
        uint            lock_flags,
        xfs_inode_t     **ipp)
 {
@@ -106,9 +107,8 @@ xfs_trans_iget(
         * If the transaction pointer is NULL, just call the normal
         * xfs_iget().
         */
-       if (tp == NULL) {
-               return (xfs_iget(mp, NULL, ino, lock_flags, ipp, 0));
-       }
+       if (tp == NULL)
+               return xfs_iget(mp, NULL, ino, flags, lock_flags, ipp, 0);
 
        /*
         * If we find the inode in core with this transaction
@@ -148,7 +148,7 @@ xfs_trans_iget(
        }
 
        ASSERT(lock_flags & XFS_ILOCK_EXCL);
-       error = xfs_iget(tp->t_mountp, tp, ino, lock_flags, &ip, 0);
+       error = xfs_iget(tp->t_mountp, tp, ino, flags, lock_flags, &ip, 0);
        if (error) {
                return error;
        }
@@ -186,7 +186,6 @@ xfs_trans_iget(
        return 0;
 }
 
-
 /*
  * Add the locked inode to the transaction.
  * The inode must be locked, and it cannot be associated with any
index 4c4bd6b..816b945 100644 (file)
@@ -110,7 +110,7 @@ xfs_dir_lookup_int(
                 * reservation in the inactive routine.
                 */
                xfs_iunlock(dp, lock_mode);
-               error = xfs_iget(dp->i_mount, NULL, *inum, 0, ipp, 0);
+               error = xfs_iget(dp->i_mount, NULL, *inum, 0, 0, ipp, 0);
                xfs_ilock(dp, lock_mode);
 
                if (error) {
index e4a0f1e..6dd9ddc 100644 (file)
@@ -64,7 +64,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20040816
+#define ACPI_CA_VERSION                 0x20041105
 
 /*
  * OS name, used for the _OS object.  The _OS object is essentially obsolete,
index 658c5f5..91f0632 100644 (file)
@@ -386,11 +386,6 @@ void ACPI_SYSTEM_XFACE
 acpi_db_execute_thread (
        void                            *context);
 
-acpi_status
-acpi_db_user_commands (
-       char                            prompt,
-       union acpi_parse_object         *op);
-
 void
 acpi_db_display_help (
        char                            *help_type);
index e003a4f..a47a162 100644 (file)
@@ -62,10 +62,12 @@ acpi_ds_obj_stack_pop (
        u32                             pop_count,
        struct acpi_walk_state          *walk_state);
 
+#ifdef ACPI_FUTURE_USAGE
 void *
 acpi_ds_obj_stack_get_value (
        u32                             index,
        struct acpi_walk_state          *walk_state);
+#endif
 
 acpi_status
 acpi_ds_obj_stack_pop_object (
@@ -248,11 +250,13 @@ u8
 acpi_ds_is_method_value (
        union acpi_operand_object       *obj_desc);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_object_type
 acpi_ds_method_data_get_type (
        u16                             opcode,
        u32                             index,
        struct acpi_walk_state          *walk_state);
+#endif
 
 acpi_status
 acpi_ds_method_data_get_value (
@@ -440,9 +444,11 @@ acpi_ds_init_aml_walk (
        struct acpi_parameter_info      *info,
        u32                             pass_number);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_ds_obj_stack_delete_all (
        struct acpi_walk_state          *walk_state);
+#endif
 
 acpi_status
 acpi_ds_obj_stack_pop_and_delete (
@@ -482,6 +488,7 @@ void
 acpi_ds_delete_walk_state_cache (
        void);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_ds_result_insert (
        void                            *object,
@@ -493,6 +500,7 @@ acpi_ds_result_remove (
        union acpi_operand_object       **object,
        u32                             index,
        struct acpi_walk_state          *walk_state);
+#endif
 
 acpi_status
 acpi_ds_result_pop (
index eb16ee2..29341a8 100644 (file)
@@ -92,7 +92,10 @@ extern      u32                                 acpi_gbl_nesting_level;
 /*
  * Enable "slack" in the AML interpreter?  Default is FALSE, and the
  * interpreter strictly follows the ACPI specification.  Setting to TRUE
- * allows the interpreter to forgive certain bad AML constructs.
+ * allows the interpreter to forgive certain bad AML constructs.  Currently:
+ * 1) Allow "implicit return" of last value in a control method
+ * 2) Allow access beyond end of operation region
+ * 3) Allow access to uninitialized locals/args (auto-init to integer 0)
  */
 ACPI_EXTERN u8       ACPI_INIT_GLOBAL (acpi_gbl_enable_interpreter_slack, FALSE);
 
@@ -180,6 +183,7 @@ ACPI_EXTERN struct acpi_mutex_info              acpi_gbl_mutex_info[NUM_MUTEX];
 ACPI_EXTERN struct acpi_memory_list             acpi_gbl_memory_lists[ACPI_NUM_MEM_LISTS];
 ACPI_EXTERN struct acpi_object_notify_handler   acpi_gbl_device_notify;
 ACPI_EXTERN struct acpi_object_notify_handler   acpi_gbl_system_notify;
+ACPI_EXTERN acpi_exception_handler              acpi_gbl_exception_handler;
 ACPI_EXTERN acpi_init_handler                   acpi_gbl_init_handler;
 ACPI_EXTERN struct acpi_walk_state             *acpi_gbl_breakpoint_walk;
 ACPI_EXTERN acpi_handle                         acpi_gbl_global_lock_semaphore;
index cf55493..819630d 100644 (file)
@@ -131,10 +131,12 @@ acpi_hw_clear_gpe_block (
        struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
        struct acpi_gpe_block_info      *gpe_block);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_hw_get_gpe_status (
        struct acpi_gpe_event_info      *gpe_event_info,
        acpi_event_status               *event_status);
+#endif
 
 acpi_status
 acpi_hw_disable_all_gpes (
@@ -161,6 +163,7 @@ acpi_hw_enable_wakeup_gpe_block (
 
 /* ACPI Timer prototypes */
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_get_timer_resolution (
        u32                             *resolution);
@@ -174,6 +177,6 @@ acpi_get_timer_duration (
        u32                             start_ticks,
        u32                             end_ticks,
        u32                             *time_elapsed);
-
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 #endif /* __ACHWARE_H__ */
index a43e91f..73c239a 100644 (file)
@@ -83,21 +83,25 @@ acpi_status
 acpi_ex_convert_to_integer (
        union acpi_operand_object       *obj_desc,
        union acpi_operand_object       **result_desc,
-       struct acpi_walk_state          *walk_state);
+       u32                             flags);
 
 acpi_status
 acpi_ex_convert_to_buffer (
        union acpi_operand_object       *obj_desc,
-       union acpi_operand_object       **result_desc,
-       struct acpi_walk_state          *walk_state);
+       union acpi_operand_object       **result_desc);
 
 acpi_status
 acpi_ex_convert_to_string (
        union acpi_operand_object       *obj_desc,
        union acpi_operand_object       **result_desc,
-       u32                             base,
-       u32                             max_length,
-       struct acpi_walk_state          *walk_state);
+       u32                             type);
+
+/* Types for ->String conversion */
+
+#define ACPI_EXPLICIT_BYTE_COPY         0x00000000
+#define ACPI_EXPLICIT_CONVERT_HEX       0x00000001
+#define ACPI_IMPLICIT_CONVERT_HEX       0x00000002
+#define ACPI_EXPLICIT_CONVERT_DECIMAL   0x00000003
 
 acpi_status
 acpi_ex_convert_to_target_type (
@@ -109,7 +113,7 @@ acpi_ex_convert_to_target_type (
 u32
 acpi_ex_convert_to_ascii (
        acpi_integer                    integer,
-       u32                             base,
+       u16                             base,
        u8                              *string,
        u8                              max_length);
 
@@ -243,11 +247,19 @@ acpi_ex_do_concatenate (
        union acpi_operand_object       **actual_return_desc,
        struct acpi_walk_state          *walk_state);
 
-u8
+acpi_status
+acpi_ex_do_logical_numeric_op (
+       u16                             opcode,
+       acpi_integer                    integer0,
+       acpi_integer                    integer1,
+       u8                              *logical_result);
+
+acpi_status
 acpi_ex_do_logical_op (
        u16                             opcode,
-       union acpi_operand_object       *obj_desc,
-       union acpi_operand_object       *obj_desc2);
+       union acpi_operand_object       *operand0,
+       union acpi_operand_object       *operand1,
+       u8                              *logical_result);
 
 acpi_integer
 acpi_ex_do_math_op (
@@ -374,7 +386,7 @@ acpi_ex_system_do_notify_op (
 
 acpi_status
 acpi_ex_system_do_suspend(
-       u32                             time);
+       acpi_integer                    time);
 
 acpi_status
 acpi_ex_system_do_stall (
@@ -412,6 +424,10 @@ acpi_ex_system_wait_semaphore (
  * exmonadic - ACPI AML (p-code) execution, monadic operators
  */
 
+acpi_status
+acpi_ex_opcode_0A_0T_1R (
+       struct acpi_walk_state          *walk_state);
+
 acpi_status
 acpi_ex_opcode_1A_0T_0R (
        struct acpi_walk_state          *walk_state);
@@ -470,12 +486,13 @@ acpi_ex_resolve_object_to_value (
 
 
 /*
- * exdump - Scanner debug output routines
+ * exdump - Interpreter debug output routines
  */
 
 void
 acpi_ex_dump_operand (
-       union acpi_operand_object       *entry_desc);
+       union acpi_operand_object       *obj_desc,
+       u32                             depth);
 
 void
 acpi_ex_dump_operands (
@@ -487,6 +504,7 @@ acpi_ex_dump_operands (
        char                            *module_name,
        u32                             line_number);
 
+#ifdef ACPI_FUTURE_USAGE
 void
 acpi_ex_dump_object_descriptor (
        union acpi_operand_object       *object,
@@ -516,7 +534,7 @@ void
 acpi_ex_out_address (
        char                            *title,
        acpi_physical_address           value);
-
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 /*
  * exnames - interpreter/scanner name load/execute
index 2afff11..da7dbb9 100644 (file)
@@ -53,7 +53,7 @@ typedef u32                                     acpi_mutex_handle;
 
 /* Total number of aml opcodes defined */
 
-#define AML_NUM_OPCODES                 0x7E
+#define AML_NUM_OPCODES                 0x7F
 
 
 /*****************************************************************************
index 43c474a..25cd645 100644 (file)
 
 /* Stack and buffer dumping */
 
-#define ACPI_DUMP_STACK_ENTRY(a)        acpi_ex_dump_operand(a)
+#define ACPI_DUMP_STACK_ENTRY(a)        acpi_ex_dump_operand((a),0)
 #define ACPI_DUMP_OPERANDS(a,b,c,d,e)   acpi_ex_dump_operands(a,b,c,d,e,_THIS_MODULE,__LINE__)
 
 
 #define ACPI_DUMP_ENTRY(a,b)            acpi_ns_dump_entry (a,b)
+
+#ifdef ACPI_FUTURE_USAGE
 #define ACPI_DUMP_TABLES(a,b)           acpi_ns_dump_tables(a,b)
+#endif
+
 #define ACPI_DUMP_PATHNAME(a,b,c,d)     acpi_ns_dump_pathname(a,b,c,d)
 #define ACPI_DUMP_RESOURCE_LIST(a)      acpi_rs_dump_resource_list(a)
 #define ACPI_DUMP_BUFFER(a,b)           acpi_ut_dump_buffer((u8 *)a,b,DB_BYTE_DISPLAY,_COMPONENT)
 #define ACPI_DUMP_STACK_ENTRY(a)
 #define ACPI_DUMP_OPERANDS(a,b,c,d,e)
 #define ACPI_DUMP_ENTRY(a,b)
+
+#ifdef ACPI_FUTURE_USAGE
 #define ACPI_DUMP_TABLES(a,b)
+#endif
+
 #define ACPI_DUMP_PATHNAME(a,b,c,d)
 #define ACPI_DUMP_RESOURCE_LIST(a)
 #define ACPI_DUMP_BUFFER(a,b)
index 8cfd1af..f0a34ef 100644 (file)
@@ -210,6 +210,7 @@ acpi_ns_remove_reference (
  * Namespace modification - nsmodify
  */
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_ns_unload_namespace (
        acpi_handle                     handle);
@@ -217,16 +218,19 @@ acpi_ns_unload_namespace (
 acpi_status
 acpi_ns_delete_subtree (
        acpi_handle                     start_handle);
+#endif
 
 
 /*
  * Namespace dump/print utilities - nsdump
  */
 
+#ifdef ACPI_FUTURE_USAGE
 void
 acpi_ns_dump_tables (
        acpi_handle                     search_base,
        u32                             max_depth);
+#endif
 
 void
 acpi_ns_dump_entry (
@@ -245,6 +249,7 @@ acpi_ns_print_pathname (
        u32                             num_segments,
        char                            *pathname);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_ns_dump_one_device (
        acpi_handle                     obj_handle,
@@ -255,6 +260,7 @@ acpi_ns_dump_one_device (
 void
 acpi_ns_dump_root_devices (
        void);
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 acpi_status
 acpi_ns_dump_one_object (
@@ -263,6 +269,7 @@ acpi_ns_dump_one_object (
        void                            *context,
        void                            **return_value);
 
+#ifdef ACPI_FUTURE_USAGE
 void
 acpi_ns_dump_objects (
        acpi_object_type                type,
@@ -270,6 +277,7 @@ acpi_ns_dump_objects (
        u32                             max_depth,
        u32                             ownder_id,
        acpi_handle                     start_handle);
+#endif
 
 
 /*
@@ -303,9 +311,11 @@ acpi_ns_get_object_value (
  * Parent/Child/Peer utility functions
  */
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_name
 acpi_ns_find_parent_name (
        struct acpi_namespace_node      *node_to_search);
+#endif
 
 
 /*
index 0d47972..09d6a5a 100644 (file)
@@ -135,7 +135,10 @@ struct acpi_object_integer
        acpi_integer                            value;
 };
 
-
+/*
+ * Note: The String and Buffer object must be identical through the Pointer
+ * element.  There is code that depends on this.
+ */
 struct acpi_object_string           /* Null terminated, ASCII characters only */
 {
        ACPI_OBJECT_COMMON_HEADER
index 42cc5b4..65d041a 100644 (file)
@@ -247,6 +247,7 @@ acpi_ps_get_arg(
        union acpi_parse_object         *op,
        u32                              argn);
 
+#ifdef ACPI_FUTURE_USAGE
 union acpi_parse_object *
 acpi_ps_get_child (
        union acpi_parse_object         *op);
@@ -255,6 +256,7 @@ union acpi_parse_object *
 acpi_ps_get_depth_next (
        union acpi_parse_object         *origin,
        union acpi_parse_object         *op);
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 
 /* pswalk - parse tree walk routines */
@@ -313,9 +315,11 @@ u8
 acpi_ps_is_prefix_char (
        u32                             c);
 
+#ifdef ACPI_FUTURE_USAGE
 u32
 acpi_ps_get_name(
        union acpi_parse_object         *op);
+#endif
 
 void
 acpi_ps_set_name(
index 86513a0..002a964 100644 (file)
@@ -104,6 +104,8 @@ typedef int (*acpi_op_suspend)      (struct acpi_device *device, int state);
 typedef int (*acpi_op_resume)  (struct acpi_device *device, int state);
 typedef int (*acpi_op_scan)    (struct acpi_device *device);
 typedef int (*acpi_op_bind)    (struct acpi_device *device);
+typedef int (*acpi_op_match)   (struct acpi_device *device,
+                                struct acpi_driver *driver);
 
 struct acpi_device_ops {
        acpi_op_add             add;
@@ -115,6 +117,7 @@ struct acpi_device_ops {
        acpi_op_resume          resume;
        acpi_op_scan            scan;
        acpi_op_bind            bind;
+       acpi_op_match           match;
 };
 
 struct acpi_driver {
@@ -322,6 +325,7 @@ int acpi_bus_receive_event (struct acpi_bus_event *event);
 int acpi_bus_register_driver (struct acpi_driver *driver);
 int acpi_bus_unregister_driver (struct acpi_driver *driver);
 
+int acpi_match_ids (struct acpi_device *device, char   *ids);
 int acpi_create_dir(struct acpi_device *);
 void acpi_remove_dir(struct acpi_device *);
 
index 54ae84d..1b6eff5 100644 (file)
@@ -70,9 +70,11 @@ acpi_status
 acpi_terminate (
        void);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_subsystem_status (
        void);
+#endif
 
 acpi_status
 acpi_enable (
@@ -82,9 +84,11 @@ acpi_status
 acpi_disable (
        void);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_get_system_info (
        struct acpi_buffer              *ret_buffer);
+#endif
 
 const char *
 acpi_format_exception (
@@ -94,10 +98,12 @@ acpi_status
 acpi_purge_cached_objects (
        void);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_install_initialization_handler (
        acpi_init_handler               handler,
        u32                             function);
+#endif
 
 /*
  * ACPI Memory manager
@@ -129,6 +135,7 @@ acpi_status
 acpi_load_tables (
        void);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_load_table (
        struct acpi_table_header        *table_ptr);
@@ -142,6 +149,7 @@ acpi_get_table_header (
        acpi_table_type                 table_type,
        u32                             instance,
        struct acpi_table_header        *out_table_header);
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 acpi_status
 acpi_get_table (
@@ -218,6 +226,7 @@ acpi_evaluate_object (
        struct acpi_object_list         *parameter_objects,
        struct acpi_buffer              *return_object_buffer);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_evaluate_object_typed (
        acpi_handle                     object,
@@ -225,6 +234,7 @@ acpi_evaluate_object_typed (
        struct acpi_object_list         *external_params,
        struct acpi_buffer              *return_buffer,
        acpi_object_type                return_type);
+#endif
 
 acpi_status
 acpi_get_object_info (
@@ -299,6 +309,17 @@ acpi_install_gpe_handler (
        acpi_event_handler              address,
        void                            *context);
 
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_install_exception_handler (
+       acpi_exception_handler          handler);
+#endif
+
+
+/*
+ * Event interfaces
+ */
+
 acpi_status
 acpi_acquire_global_lock (
        u16                             timeout,
@@ -324,6 +345,7 @@ acpi_disable_event (
        u32                             event,
        u32                             flags);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_clear_event (
        u32                             event);
@@ -332,6 +354,7 @@ acpi_status
 acpi_get_event_status (
        u32                             event,
        acpi_event_status               *event_status);
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 acpi_status
 acpi_set_gpe_type (
@@ -357,12 +380,14 @@ acpi_clear_gpe (
        u32                             gpe_number,
        u32                             flags);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_get_gpe_status (
        acpi_handle                     gpe_device,
        u32                             gpe_number,
        u32                             flags,
        acpi_event_status               *event_status);
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 acpi_status
 acpi_install_gpe_block (
@@ -391,10 +416,12 @@ acpi_get_current_resources(
        acpi_handle                     device_handle,
        struct acpi_buffer              *ret_buffer);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_get_possible_resources(
        acpi_handle                     device_handle,
        struct acpi_buffer              *ret_buffer);
+#endif
 
 acpi_status
 acpi_walk_resources (
@@ -438,9 +465,11 @@ acpi_status
 acpi_set_firmware_waking_vector (
        acpi_physical_address           physical_address);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_get_firmware_waking_vector (
        acpi_physical_address           *physical_address);
+#endif
 
 acpi_status
 acpi_get_sleep_type_data (
index e1a9187..bcefb3b 100644 (file)
@@ -60,10 +60,12 @@ acpi_rs_get_crs_method_data (
        acpi_handle                     handle,
        struct acpi_buffer              *ret_buffer);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_rs_get_prs_method_data (
        acpi_handle                     handle,
        struct acpi_buffer              *ret_buffer);
+#endif
 
 acpi_status
 acpi_rs_get_method_data (
@@ -95,6 +97,7 @@ acpi_rs_create_pci_routing_table (
 /*
  * Function prototypes called from acpi_rs_create*
  */
+#ifdef ACPI_FUTURE_USAGE
 void
 acpi_rs_dump_irq (
        union acpi_resource_data        *data);
@@ -154,6 +157,7 @@ acpi_rs_dump_resource_list (
 void
 acpi_rs_dump_irq_list (
        u8                              *route_table);
+#endif  /*  ACPI_FUTURE_USAGE  */
 
 acpi_status
 acpi_rs_get_byte_stream_start (
index 43112ab..b95bd65 100644 (file)
 #define SIZE_IN_HEADER          0
 
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_tb_handle_to_object (
        u16                             table_id,
        struct acpi_table_desc          **table_desc);
+#endif
 
 /*
  * tbconvrt - Table conversion routines
index b380c23..3647911 100644 (file)
@@ -330,6 +330,8 @@ struct acpi_table_support
 #include "actbl1.h"   /* Acpi 1.0 table definitions */
 #include "actbl2.h"   /* Acpi 2.0 table definitions */
 
+extern u8 acpi_fadt_is_v1; /* is set to 1 if FADT is revision 1,
+                           * needed for certain workarounds */
 
 #pragma pack(1)
 /*
index 8bee457..9db2f17 100644 (file)
@@ -303,7 +303,7 @@ struct uint32_struct
 typedef u32                                     acpi_integer;
 #define ACPI_INTEGER_MAX                ACPI_UINT32_MAX
 #define ACPI_INTEGER_BIT_SIZE           32
-#define ACPI_MAX_DECIMAL_DIGITS         10
+#define ACPI_MAX_DECIMAL_DIGITS         10  /* 2^32 = 4,294,967,296 */
 
 #define ACPI_USE_NATIVE_DIVIDE          /* Use compiler native 32-bit divide */
 
@@ -315,13 +315,18 @@ typedef u32                                     acpi_integer;
 typedef u64                                     acpi_integer;
 #define ACPI_INTEGER_MAX                ACPI_UINT64_MAX
 #define ACPI_INTEGER_BIT_SIZE           64
-#define ACPI_MAX_DECIMAL_DIGITS         19
+#define ACPI_MAX_DECIMAL_DIGITS         20  /* 2^64 = 18,446,744,073,709,551,616 */
+
 
 #if ACPI_MACHINE_WIDTH == 64
 #define ACPI_USE_NATIVE_DIVIDE          /* Use compiler native 64-bit divide */
 #endif
 #endif
 
+#define ACPI_MAX64_DECIMAL_DIGITS       20
+#define ACPI_MAX32_DECIMAL_DIGITS       10
+#define ACPI_MAX16_DECIMAL_DIGITS        5
+#define ACPI_MAX8_DECIMAL_DIGITS         3
 
 /*
  * Constants with special meanings
@@ -831,6 +836,14 @@ acpi_status (*acpi_init_handler) (
 
 #define ACPI_INIT_DEVICE_INI        1
 
+typedef
+acpi_status (*acpi_exception_handler) (
+       acpi_status                     aml_status,
+       acpi_name                       name,
+       u16                             opcode,
+       u32                             aml_offset,
+       void                            *context);
+
 
 /* Address Spaces (For Operation Regions) */
 
index d786ae5..1786282 100644 (file)
@@ -177,6 +177,12 @@ acpi_ut_strncpy (
        const char                      *src_string,
        acpi_size                       count);
 
+int
+acpi_ut_memcmp (
+       const char                      *buffer1,
+       const char                      *buffer2,
+       acpi_size                       count);
+
 int
 acpi_ut_strncmp (
        const char                      *string1,
@@ -577,6 +583,10 @@ union acpi_operand_object *
 acpi_ut_create_buffer_object (
        acpi_size                       buffer_size);
 
+union acpi_operand_object *
+acpi_ut_create_string_object (
+       acpi_size                       string_size);
+
 
 /*
  * ut_ref_cnt - Object reference count management
@@ -656,12 +666,14 @@ acpi_ut_create_update_state_and_push (
        u16                             action,
        union acpi_generic_state        **state_list);
 
+#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_ut_create_pkg_state_and_push (
        void                            *internal_object,
        void                            *external_object,
        u16                             index,
        union acpi_generic_state        **state_list);
+#endif
 
 union acpi_generic_state *
 acpi_ut_create_control_state (
@@ -690,14 +702,14 @@ acpi_ut_print_string (
 
 acpi_status
 acpi_ut_divide (
-       acpi_integer                    *in_dividend,
-       acpi_integer                    *in_divisor,
+       acpi_integer                    in_dividend,
+       acpi_integer                    in_divisor,
        acpi_integer                    *out_quotient,
        acpi_integer                    *out_remainder);
 
 acpi_status
 acpi_ut_short_divide (
-       acpi_integer                    *in_dividend,
+       acpi_integer                    in_dividend,
        u32                             divisor,
        acpi_integer                    *out_quotient,
        u32                             *out_remainder);
@@ -716,9 +728,15 @@ acpi_ut_strtoul64 (
        u32                             base,
        acpi_integer                    *ret_integer);
 
+/* Values for Base above (16=Hex, 10=Decimal) */
+
+#define ACPI_ANY_BASE        0
+
+#ifdef ACPI_FUTURE_USAGE
 char *
 acpi_ut_strupr (
        char                            *src_string);
+#endif
 
 u8 *
 acpi_ut_get_resource_end_tag (
@@ -837,9 +855,11 @@ acpi_ut_remove_allocation (
        char                            *module,
        u32                             line);
 
+#ifdef ACPI_FUTURE_USAGE
 void
 acpi_ut_dump_allocation_info (
        void);
+#endif
 
 void
 acpi_ut_dump_allocations (
index 0344b94..c4fa67d 100644 (file)
 #define AML_REVISION_OP             (u16) 0x5b30
 #define AML_DEBUG_OP                (u16) 0x5b31
 #define AML_FATAL_OP                (u16) 0x5b32
+#define AML_TIMER_OP                (u16) 0x5b33     /* ACPI 3.0 */
 #define AML_REGION_OP               (u16) 0x5b80
 #define AML_FIELD_OP                (u16) 0x5b81
 #define AML_DEVICE_OP               (u16) 0x5b82
 
 /* Opcode flags */
 
-#define AML_HAS_ARGS                0x0800
-#define AML_HAS_TARGET              0x0400
-#define AML_HAS_RETVAL              0x0200
-#define AML_NSOBJECT                0x0100
-#define AML_NSOPCODE                0x0080
-#define AML_NSNODE                  0x0040
-#define AML_NAMED                   0x0020
-#define AML_DEFER                   0x0010
-#define AML_FIELD                   0x0008
-#define AML_CREATE                  0x0004
-#define AML_MATH                    0x0002
 #define AML_LOGICAL                 0x0001
-#define AML_CONSTANT                0x1000
+#define AML_LOGICAL_NUMERIC         0x0002
+#define AML_MATH                    0x0004
+#define AML_CREATE                  0x0008
+#define AML_FIELD                   0x0010
+#define AML_DEFER                   0x0020
+#define AML_NAMED                   0x0040
+#define AML_NSNODE                  0x0080
+#define AML_NSOPCODE                0x0100
+#define AML_NSOBJECT                0x0200
+#define AML_HAS_RETVAL              0x0400
+#define AML_HAS_TARGET              0x0800
+#define AML_HAS_ARGS                0x1000
+#define AML_CONSTANT                0x2000
 
 /* Convenient flag groupings */
 
+#define AML_FLAGS_EXEC_0A_0T_1R                                     AML_HAS_RETVAL
 #define AML_FLAGS_EXEC_1A_0T_0R     AML_HAS_ARGS                                   /* Monadic1  */
 #define AML_FLAGS_EXEC_1A_0T_1R     AML_HAS_ARGS |                  AML_HAS_RETVAL /* Monadic2  */
 #define AML_FLAGS_EXEC_1A_1T_0R     AML_HAS_ARGS | AML_HAS_TARGET
  * The opcode Type is used in a dispatch table, do not change
  * without updating the table.
  */
-#define AML_TYPE_EXEC_1A_0T_0R      0x00 /* Monadic1  */
-#define AML_TYPE_EXEC_1A_0T_1R      0x01 /* Monadic2  */
-#define AML_TYPE_EXEC_1A_1T_0R      0x02
-#define AML_TYPE_EXEC_1A_1T_1R      0x03 /* monadic2_r */
-#define AML_TYPE_EXEC_2A_0T_0R      0x04 /* Dyadic1   */
-#define AML_TYPE_EXEC_2A_0T_1R      0x05 /* Dyadic2   */
-#define AML_TYPE_EXEC_2A_1T_1R      0x06 /* dyadic2_r  */
-#define AML_TYPE_EXEC_2A_2T_1R      0x07
-#define AML_TYPE_EXEC_3A_0T_0R      0x08
-#define AML_TYPE_EXEC_3A_1T_1R      0x09
-#define AML_TYPE_EXEC_6A_0T_1R      0x0A
+#define AML_TYPE_EXEC_0A_0T_1R      0x00
+#define AML_TYPE_EXEC_1A_0T_0R      0x01 /* Monadic1  */
+#define AML_TYPE_EXEC_1A_0T_1R      0x02 /* Monadic2  */
+#define AML_TYPE_EXEC_1A_1T_0R      0x03
+#define AML_TYPE_EXEC_1A_1T_1R      0x04 /* monadic2_r */
+#define AML_TYPE_EXEC_2A_0T_0R      0x05 /* Dyadic1   */
+#define AML_TYPE_EXEC_2A_0T_1R      0x06 /* Dyadic2   */
+#define AML_TYPE_EXEC_2A_1T_1R      0x07 /* dyadic2_r  */
+#define AML_TYPE_EXEC_2A_2T_1R      0x08
+#define AML_TYPE_EXEC_3A_0T_0R      0x09
+#define AML_TYPE_EXEC_3A_1T_1R      0x0A
+#define AML_TYPE_EXEC_6A_0T_1R      0x0B
 /* End of types used in dispatch table */
 
 #define AML_TYPE_LITERAL            0x0B
index b28b690..89a52dd 100644 (file)
@@ -99,7 +99,7 @@ struct asl_resource_node
 /*
  * Resource descriptors defined in the ACPI specification.
  *
- * Alignment must be BYTE because these descriptors
+ * Packing/alignment must be BYTE because these descriptors
  * are used to overlay the AML byte stream.
  */
 #pragma pack(1)
@@ -297,7 +297,7 @@ struct asl_general_register_desc
 
 #pragma pack()
 
-/* Union of all resource descriptors, sow we can allocate the worst case */
+/* Union of all resource descriptors, so we can allocate the worst case */
 
 union asl_resource_desc
 {
index 7964aaf..42fb804 100644 (file)
  */
 
 #define ACPI_STRSTR(s1,s2)      strstr((s1), (s2))
+
+#ifdef ACPI_FUTURE_USAGE
 #define ACPI_STRUPR(s)          (void) acpi_ut_strupr ((s))
+#endif
+
 #define ACPI_STRLEN(s)          (acpi_size) strlen((s))
 #define ACPI_STRCPY(d,s)        (void) strcpy((d), (s))
 #define ACPI_STRNCPY(d,s,n)     (void) strncpy((d), (s), (acpi_size)(n))
 #define ACPI_STRCAT(d,s)        (void) strcat((d), (s))
 #define ACPI_STRNCAT(d,s,n)     strncat((d), (s), (acpi_size)(n))
 #define ACPI_STRTOUL(d,s,n)     strtoul((d), (s), (acpi_size)(n))
+#define ACPI_MEMCMP(s1,s2,n)    memcmp((s1), (s2), (acpi_size)(n))
 #define ACPI_MEMCPY(d,s,n)      (void) memcpy((d), (s), (acpi_size)(n))
 #define ACPI_MEMSET(d,s,n)      (void) memset((d), (s), (acpi_size)(n))
 
@@ -286,7 +291,11 @@ typedef char *va_list;
 
 
 #define ACPI_STRSTR(s1,s2)      acpi_ut_strstr ((s1), (s2))
+
+#ifdef ACPI_FUTURE_USAGE
 #define ACPI_STRUPR(s)          (void) acpi_ut_strupr ((s))
+#endif
+
 #define ACPI_STRLEN(s)          (acpi_size) acpi_ut_strlen ((s))
 #define ACPI_STRCPY(d,s)        (void) acpi_ut_strcpy ((d), (s))
 #define ACPI_STRNCPY(d,s,n)     (void) acpi_ut_strncpy ((d), (s), (acpi_size)(n))
@@ -295,6 +304,7 @@ typedef char *va_list;
 #define ACPI_STRCAT(d,s)        (void) acpi_ut_strcat ((d), (s))
 #define ACPI_STRNCAT(d,s,n)     acpi_ut_strncat ((d), (s), (acpi_size)(n))
 #define ACPI_STRTOUL(d,s,n)     acpi_ut_strtoul ((d), (s), (acpi_size)(n))
+#define ACPI_MEMCMP(s1,s2,n)    acpi_ut_memcmp((s1), (s2), (acpi_size)(n))
 #define ACPI_MEMCPY(d,s,n)      (void) acpi_ut_memcpy ((d), (s), (acpi_size)(n))
 #define ACPI_MEMSET(d,v,n)      (void) acpi_ut_memset ((d), (v), (acpi_size)(n))
 #define ACPI_TOUPPER            acpi_ut_to_upper
index dab7521..3982834 100644 (file)
@@ -17,7 +17,7 @@
 
 struct acpi_processor_cx_policy {
        u32                     count;
-       int                     state;
+       u32                     state;
        struct {
                u32                     time;
                u32                     ticks;
@@ -38,8 +38,8 @@ struct acpi_processor_cx {
 };
 
 struct acpi_processor_power {
-       int                     state;
-       int                     default_state;
+       u32                     state;
+       u32                     default_state;
        u32                     bm_activity;
        struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
 };
@@ -140,4 +140,8 @@ extern void acpi_processor_unregister_performance (
        struct acpi_processor_performance * performance,
        unsigned int cpu);
 
+/* note: this locks both the calling module and the processor module
+         if a _PPC object exists, rmmod is disallowed then */
+int acpi_processor_notify_smm(struct module *calling_module);
+
 #endif
index 549550f..3a70d68 100644 (file)
@@ -347,14 +347,14 @@ __EXTERN_INLINE unsigned int cia_ioread8(void __iomem *xaddr)
        unsigned long addr = (unsigned long) xaddr;
        unsigned long result, base_and_type;
 
-       /* We can use CIA_MEM_R1_MASK for io ports too, since it is large
-          enough to cover all io ports, and smaller than CIA_IO.  */
-       addr &= CIA_MEM_R1_MASK;
        if (addr >= CIA_DENSE_MEM)
                base_and_type = CIA_SPARSE_MEM + 0x00;
        else
                base_and_type = CIA_IO + 0x00;
 
+       /* We can use CIA_MEM_R1_MASK for io ports too, since it is large
+          enough to cover all io ports, and smaller than CIA_IO.  */
+       addr &= CIA_MEM_R1_MASK;
        result = *(vip) ((addr << 5) + base_and_type);
        return __kernel_extbl(result, addr & 3);
 }
@@ -364,12 +364,12 @@ __EXTERN_INLINE void cia_iowrite8(u8 b, void __iomem *xaddr)
        unsigned long addr = (unsigned long) xaddr;
        unsigned long w, base_and_type;
 
-       addr &= CIA_MEM_R1_MASK;
        if (addr >= CIA_DENSE_MEM)
                base_and_type = CIA_SPARSE_MEM + 0x00;
        else
                base_and_type = CIA_IO + 0x00;
 
+       addr &= CIA_MEM_R1_MASK;
        w = __kernel_insbl(b, addr & 3);
        *(vuip) ((addr << 5) + base_and_type) = w;
 }
@@ -379,12 +379,12 @@ __EXTERN_INLINE unsigned int cia_ioread16(void __iomem *xaddr)
        unsigned long addr = (unsigned long) xaddr;
        unsigned long result, base_and_type;
 
-       addr &= CIA_MEM_R1_MASK;
        if (addr >= CIA_DENSE_MEM)
                base_and_type = CIA_SPARSE_MEM + 0x08;
        else
                base_and_type = CIA_IO + 0x08;
 
+       addr &= CIA_MEM_R1_MASK;
        result = *(vip) ((addr << 5) + base_and_type);
        return __kernel_extwl(result, addr & 3);
 }
@@ -394,12 +394,12 @@ __EXTERN_INLINE void cia_iowrite16(u16 b, void __iomem *xaddr)
        unsigned long addr = (unsigned long) xaddr;
        unsigned long w, base_and_type;
 
-       addr &= CIA_MEM_R1_MASK;
        if (addr >= CIA_DENSE_MEM)
                base_and_type = CIA_SPARSE_MEM + 0x08;
        else
                base_and_type = CIA_IO + 0x08;
 
+       addr &= CIA_MEM_R1_MASK;
        w = __kernel_inswl(b, addr & 3);
        *(vuip) ((addr << 5) + base_and_type) = w;
 }
index 677dc9b..c85ab6b 100644 (file)
 
 #define ENOMEDIUM      129     /* No medium found */
 #define EMEDIUMTYPE    130     /* Wrong medium type */
+#define        ECANCELED       131     /* Operation Cancelled */
+#define        ENOKEY          132     /* Required key not available */
+#define        EKEYEXPIRED     133     /* Key has expired */
+#define        EKEYREVOKED     134     /* Key has been revoked */
+#define        EKEYREJECTED    135     /* Key was rejected by service */
 
 #endif
index 10be402..de7e476 100644 (file)
@@ -16,29 +16,8 @@ typedef struct {
 
 #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-27 are the hardirq count (max # of hardirqs: 4096)
- *
- * - ( bit 30 is the PREEMPT_ACTIVE flag. )
- *
- * PREEMPT_MASK: 0x000000ff
- * SOFTIRQ_MASK: 0x0000ff00
- * HARDIRQ_MASK: 0x0fff0000
- */
-
-#define PREEMPT_BITS   8
-#define SOFTIRQ_BITS   8
 #define HARDIRQ_BITS   12
 
-#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 nestable IRQ sources in the system
index ce75633..726c150 100644 (file)
@@ -107,7 +107,7 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n)
 
 #define pfn_to_page(pfn)                                               \
 ({                                                                     \
-       unsigned long kaddr = (unsigned long)__va(pfn << PAGE_SHIFT);   \
+       unsigned long kaddr = (unsigned long)__va((pfn) << PAGE_SHIFT); \
        (node_mem_map(kvaddr_to_nid(kaddr)) + local_mapnr(kaddr));      \
 })
 
@@ -119,7 +119,7 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n)
        ((( (page) - page_zone(page)->zone_mem_map )                    \
        + page_zone(page)->zone_start_pfn) << PAGE_SHIFT)
 
-#define pfn_to_nid(pfn)                pa_to_nid(((u64)pfn << PAGE_SHIFT))
+#define pfn_to_nid(pfn)                pa_to_nid(((u64)(pfn) << PAGE_SHIFT))
 #define pfn_valid(pfn)                                                 \
        (((pfn) - node_start_pfn(pfn_to_nid(pfn))) <                    \
         node_spanned_pages(pfn_to_nid(pfn)))                                   \
index fa205d4..14d7e8d 100644 (file)
@@ -22,9 +22,9 @@
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(a)                        ((a))
-#define __mem_pci(a)           ((unsigned long)(a))
-#define __mem_isa(a)           ((unsigned long)(a))
+#define __io(a)                        ((void __iomem *)(a))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           (a)
 
 /*
  * We don't support ins[lb]/outs[lb].  Make them fault.
index 10d1038..9cb27cd 100644 (file)
@@ -30,6 +30,9 @@ p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        do_leds();
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
        do_profile(regs);
        return IRQ_HANDLED;
 }
index 8511b2c..70576b1 100644 (file)
 /*
  * Translation of various region addresses to virtual addresses
  */
-#define __io(a)                        (PCIO_BASE + (a))
+#define __io(a)                        ((void __iomem *)(PCIO_BASE + (a)))
 #if 1
-#define __mem_pci(a)           ((unsigned long)(a))
-#define __mem_isa(a)           (PCIMEM_BASE + (unsigned long)(a))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           ((a) + PCIMEM_BASE)
 #else
 
-static inline unsigned long ___mem_pci(unsigned long a)
+static inline void __iomem *___mem_pci(void __iomem *p)
 {
+       unsigned long a = (unsigned long)p;
        BUG_ON(a <= 0xc0000000 || a >= 0xe0000000);
-       return a;
+       return p;
 }
 
-static inline unsigned long ___mem_isa(unsigned long a)
+static inline void __iomem *___mem_isa(void __iomem *p)
 {
+       unsigned long a = (unsigned long)p;
        BUG_ON(a >= 16*1048576);
-       return PCIMEM_BASE + a;
+       return p + PCIMEM_BASE;
 }
-#define __mem_pci(a)           ___mem_pci((unsigned long)(a))
-#define __mem_isa(a)           ___mem_isa((unsigned long)(a))
+#define __mem_pci(a)           ___mem_pci(a)
+#define __mem_isa(a)           ___mem_isa(a)
 #endif
 
 #endif
index b93a525..1f0afa2 100644 (file)
@@ -33,7 +33,7 @@
 #define insw    __arch_readsw
 #define insl    __arch_readsl*/
 
-#define __io(a)                        (a)
+#define __io(a)                        ((void __iomem *)(a))
 #define __mem_pci(a)            (a) 
 
 #endif
index c5b737a..6881482 100644 (file)
@@ -18,7 +18,7 @@
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(a) (a)
-#define __mem_pci(a) (a)
+#define __io(a)                ((void __iomem *)(a))
+#define __mem_pci(a)   (a)
 
 #endif
index 6c8789f..28a4cca 100644 (file)
@@ -22,7 +22,7 @@
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(a)       (a)
-#define __mem_pci(a)  (a)
+#define __io(a)                ((void __iomem *)(a))
+#define __mem_pci(a)   (a)
 
 #endif
index c94b789..fbea8be 100644 (file)
@@ -22,8 +22,8 @@
 
 #define IO_SPACE_LIMIT 0xffff
 
-#define __io(a)                        (PCI_IO_VADDR + (a))
-#define __mem_pci(a)           ((unsigned long)(a))
-#define __mem_isa(a)           (PCI_MEMORY_VADDR + (unsigned long)(a))
+#define __io(a)                        ((void __iomem *)(PCI_IO_VADDR + (a)))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           ((a) + PCI_MEMORY_VADDR)
 
 #endif
index e6439c1..2761dfd 100644 (file)
@@ -13,8 +13,8 @@
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(p)                        ((p))
-#define __mem_pci(a)           ((unsigned long)(a))
-#define __mem_isa(a)           ((unsigned long)(a))
+#define __io(p)                        ((void __iomem *)(p))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           (a)
 
 #endif
index 71520c8..0fb3568 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-ixdp2400/dma.h
+ * linux/include/asm-arm/arch-ixp2000/dma.h
  *
  * Copyright (C) 2002 Intel Corp.
  *
index 7463a32..8e58f37 100644 (file)
@@ -16,7 +16,7 @@
 #define __ASM_ARM_ARCH_IO_H
 
 #define IO_SPACE_LIMIT         0xffffffff
-#define __mem_pci(a)           ((unsigned long)(a))
+#define __mem_pci(a)           (a)
 
 /*
  * Pick up VMALLOC_END
@@ -24,7 +24,7 @@
 #define ___io(p)               ((unsigned long)((p)+IXP2000_PCI_IO_VIRT_BASE))
 
 /*
- * IXP200 does not do proper byte-lane conversion for PCI addresses,
+ * IXP2000 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)))
index a6b104f..6ef0859 100644 (file)
@@ -28,7 +28,7 @@
  * 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_SOFT_INT            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_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_THDA2               18 /* thread 64-95A, IXP2800 only */
+#define        IRQ_IXP2000_THDA3               19 /* thread 96-127A, IXP2800 only */
+#define        IRQ_IXP2000_THDB0               24 /* thread 0-31B */
 #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        IRQ_IXP2000_THDB2               26 /* thread 64-95B, IXP2800 only */
+#define        IRQ_IXP2000_THDB3               27 /* thread 96-127B, IXP2800 only */
 
 /* define generic GPIOs */
 #define IRQ_IXP2000_GPIO0              32
 #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 NR_IXP2000_IRQS                 42
 
 #define        IXP2000_BOARD_IRQ(x)            (NR_IXP2000_IRQS + (x))
 
index e017826..84ca027 100644 (file)
@@ -53,7 +53,7 @@
 
 /*
  * PCI devfns for on-board devices. We need these to be able to
- * properly translte IRQs and for device removal.
+ * properly translate IRQs and for device removal.
  */
 #define        IXDP2400_SLAVE_ENET_DEVFN       0x18    /* Bus 1 */
 #define        IXDP2400_MASTER_ENET_DEVFN      0x20    /* Bus 1 */
index 626ed6b..46469c4 100644 (file)
@@ -50,4 +50,8 @@
 
 #define        IXDP2X01_UART_CLK               1843200
 
+#define        IXDP2X01_GPIO_I2C_ENABLE        0x02
+#define        IXDP2X01_GPIO_SCL               0x07
+#define        IXDP2X01_GPIO_SDA               0x06
+
 #endif /* __IXDP2x01_H__ */
index 9c8b21d..5e047b3 100644 (file)
 
 /*
  * Mask of valid IRQs in the 32-bit IRQ register. We use
- * this to mark certain IRQs as being in-valid.
+ * this to mark certain IRQs as being invalid.
  */
 #define        IXP2000_VALID_IRQ_MASK  0x0f0fffff
 
 #define        SLOWPORT_CCR_DIV_30             0x0f
 
 /*
- * PCR values.  PCR configure the mode of the interfac3
+ * PCR values.  PCR configure the mode of the interface.
  */
 #define        SLOWPORT_MODE_FLASH             0x00
 #define        SLOWPORT_MODE_LUCENT            0x01
 #define        SLOWPORT_MODE_MOTOROLA_UP       0x04
 
 /*
- * ADC values.  Defines data and address bus widths
+ * ADC values.  Defines data and address bus widths.
  */
 #define        SLOWPORT_ADDR_WIDTH_8           0x00
 #define        SLOWPORT_ADDR_WIDTH_16          0x01
 #define        SLOWPORT_DATA_WIDTH_32          0x30
 
 /*
- * Masks and shifts for various fields in the WTC and RTC registers
+ * Masks and shifts for various fields in the WTC and RTC registers.
  */
 #define        SLOWPORT_WRTC_MASK_HD           0x0003
 #define        SLOWPORT_WRTC_MASK_SU           0x003c
 
 
 /*
- * GPIO registers & GPIO interface
+ * 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)
index 9f4e315..16e4a24 100644 (file)
 #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
+ * The IXP2400 B0 silicon contains an erratum (#66) 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
+ * read or write, the first write will happen twice. OR...if it's
  * not a back-to-back trasaction, the read or write will generate 
  * incorrect data.
  *
@@ -117,6 +117,7 @@ static inline unsigned int ixp2000_is_pcimaster(void)
 void ixp2000_map_io(void);
 void ixp2000_init_irq(void);
 void ixp2000_init_time(unsigned long);
+unsigned long ixp2000_gettimeoffset(void);
 
 struct pci_sys_data;
 
index ec72ba4..281907b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-ixp2400/system.h
+ * linux/include/asm-arm/arch-ixp2000/system.h
  *
  * Copyright (C) 2002 Intel Corp.
  *
index 5400ab0..c27b9d3 100644 (file)
@@ -46,7 +46,7 @@ extern int ixp4xx_pci_write(u32 addr, u32 cmd, u32 data);
  */
 #ifndef        CONFIG_IXP4XX_INDIRECT_PCI
 
-#define __mem_pci(a)           ((unsigned long)(a))
+#define __mem_pci(a)           (a)
 
 #else
 
@@ -58,10 +58,10 @@ extern int ixp4xx_pci_write(u32 addr, u32 cmd, u32 data);
  * access registers. If something outside of PCI is ioremap'd, we
  * fallback to the default.
  */
-static inline void *
+static inline void __iomem *
 __ixp4xx_ioremap(unsigned long addr, size_t size, unsigned long flags, unsigned long align)
 {
-       extern void * __ioremap(unsigned long, size_t, unsigned long, unsigned long);
+       extern void __iomem * __ioremap(unsigned long, size_t, unsigned long, unsigned long);
        if((addr < 0x48000000) || (addr > 0x4fffffff))
                return __ioremap(addr, size, flags, align);
 
@@ -69,9 +69,9 @@ __ixp4xx_ioremap(unsigned long addr, size_t size, unsigned long flags, unsigned
 }
 
 static inline void
-__ixp4xx_iounmap(void *addr)
+__ixp4xx_iounmap(void __iomem *addr)
 {
-       extern void __iounmap(void *addr);
+       extern void __iounmap(void __iomem *addr);
 
        if ((u32)addr >= VMALLOC_START)
                __iounmap(addr);
@@ -292,7 +292,7 @@ __ixp4xx_outb(u8 value, u32 addr)
 }
 
 static inline void 
-__ixp4xx_outsb(u32 io_addr, u8 *vaddr, u32 count)
+__ixp4xx_outsb(u32 io_addr, const u8 *vaddr, u32 count)
 {
        while (count--)
                outb(*vaddr++, io_addr);
@@ -309,7 +309,7 @@ __ixp4xx_outw(u16 value, u32 addr)
 }
 
 static inline void 
-__ixp4xx_outsw(u32 io_addr, u16 *vaddr, u32 count)
+__ixp4xx_outsw(u32 io_addr, const u16 *vaddr, u32 count)
 {
        while (count--)
                outw(cpu_to_le16(*vaddr++), io_addr);
@@ -322,7 +322,7 @@ __ixp4xx_outl(u32 value, u32 addr)
 }
 
 static inline void 
-__ixp4xx_outsl(u32 io_addr, u32 *vaddr, u32 count)
+__ixp4xx_outsl(u32 io_addr, const u32 *vaddr, u32 count)
 {
        while (count--)
                outl(*vaddr++, io_addr);
index b8ea579..fc9d710 100644 (file)
@@ -53,12 +53,14 @@ struct ixp4xx_i2c_pins {
 };
 
 
+struct sys_timer;
+
 /*
  * Functions used by platform-level setup code
  */
 extern void ixp4xx_map_io(void);
 extern void ixp4xx_init_irq(void);
-extern void ixp4xx_init_time(void);
+extern struct sys_timer ixp4xx_timer;
 extern void ixp4xx_pci_preinit(void);
 struct pci_sys_data;
 extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
index 91dfdf3..fc012a3 100644 (file)
@@ -17,9 +17,9 @@
 /*
  * There are not real ISA nor PCI buses, so we fake it.
  */
-#define __io_pci(a)             (PCIO_BASE + (a))
-#define __mem_pci(a)            ((unsigned long)(a))
-#define __mem_isa(a)            ((unsigned long)(a))
+#define __io_pci(a)            ((void __iomem *)(PCIO_BASE + (a)))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           (a)
 
 #define __ioaddr(p)             __io_pci(p)
 
index 31d791a..7b98b53 100644 (file)
@@ -46,6 +46,9 @@ static irqreturn_t
 timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
        do_profile(regs);
        RTC_RTCC = 0;                           /* Clear interrupt */
 
index eeb2a3b..c13bdd9 100644 (file)
@@ -14,8 +14,8 @@
 #define IO_SPACE_LIMIT 0xffffffff
 
 /* No ISA or PCI bus on this machine. */
-#define __io(a)                        (a)
-#define __mem_pci(a)           ((unsigned long)(a))
-#define __mem_isa(a)           ((unsigned long)(a))
+#define __io(a)                        ((void __iomem *)(a))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           (a)
 
 #endif /* __ASM_ARCH_IO_H */
index e9c296e..fa726b6 100644 (file)
@@ -14,5 +14,4 @@
 
 /*
 #define CLOCK_TICK_RATE                3686400
-#define CLOCK_TICK_FACTOR      80
 */
index e51f248..9c8ad42 100644 (file)
 #define OMAP1610_ETHR_SIZE             SZ_4K
 #define OMAP1610_ETHR_START            0x04000000
 
-/* Intel STRATA NOR flash at CS3 */
-#define OMAP1610_NOR_FLASH_BASE                0xD8000000
-#define OMAP1610_NOR_FLASH_SIZE                SZ_32M
-#define OMAP1610_NOR_FLASH_START       0x0C000000
+/* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */
+#define OMAP_NOR_FLASH_SIZE             SZ_32M
+#define OMAP_NOR_FLASH_START1           0x0C000000 /* CS3 */
+#define OMAP_NOR_FLASH_START2           0x0A000000 /* CS2B */
+
+/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
+#define OMAP_NAND_FLASH_START1           0x0A000000 /* CS2B */
+#define OMAP_NAND_FLASH_START2           0x0C000000 /* CS3 */
 
 #endif /*  __ASM_ARCH_OMAP_H2_H */
 
index 80c37bf..3f48583 100644 (file)
 #define OMAP1710_ETHR_SIZE             SZ_4K
 #define OMAP1710_ETHR_START            0x04000000
 
-/* Intel STRATA NOR flash at CS3 */
-#define OMAP_NOR_FLASH_BASE            0xD8000000
-#define OMAP_NOR_FLASH_SIZE            SZ_32M
-#define OMAP_NOR_FLASH_START           0x00000000
+/* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */
+#define OMAP_NOR_FLASH_SIZE             SZ_32M
+#define OMAP_NOR_FLASH_START1          0x0C000000 /* CS3 */
+#define OMAP_NOR_FLASH_START2          0x0A000000 /* CS2B */
+
+/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
+#define OMAP_NAND_FLASH_START1           0x0A000000 /* CS2B */
+#define OMAP_NAND_FLASH_START2           0x0C000000 /* CS3 */
 
 #define MAXIRQNUM                      (IH_BOARD_BASE)
 #define MAXFIQNUM                      MAXIRQNUM
 
 #define NR_IRQS                                (MAXIRQNUM + 1)
 
-#define OMAP_MCBSP1_BASE               OMAP1610_MCBSP1_BASE
-#define AUDIO_DRR2  (OMAP_MCBSP1_BASE + 0x00)
-#define AUDIO_DRR1  (OMAP_MCBSP1_BASE + 0x02)
-#define AUDIO_DXR2  (OMAP_MCBSP1_BASE + 0x04)
-#define AUDIO_DXR1  (OMAP_MCBSP1_BASE + 0x06)
-#define AUDIO_SPCR2 (OMAP_MCBSP1_BASE + 0x08)
-#define AUDIO_SPCR1 (OMAP_MCBSP1_BASE + 0x0a)
-#define AUDIO_RCR2  (OMAP_MCBSP1_BASE + 0x0c)
-#define AUDIO_RCR1  (OMAP_MCBSP1_BASE + 0x0e)
-#define AUDIO_XCR2  (OMAP_MCBSP1_BASE + 0x10)
-#define AUDIO_XCR1  (OMAP_MCBSP1_BASE + 0x12)
-#define AUDIO_SRGR2 (OMAP_MCBSP1_BASE + 0x14)
-#define AUDIO_SRGR1 (OMAP_MCBSP1_BASE + 0x16)
-#define AUDIO_MCR2  (OMAP_MCBSP1_BASE + 0x18)
-#define AUDIO_MCR1  (OMAP_MCBSP1_BASE + 0x1a)
-#define AUDIO_RCERA (OMAP_MCBSP1_BASE + 0x1c)
-#define AUDIO_RCERB (OMAP_MCBSP1_BASE + 0x1e)
-#define AUDIO_XCERA (OMAP_MCBSP1_BASE + 0x20)
-#define AUDIO_XCERB (OMAP_MCBSP1_BASE + 0x22)
-#define AUDIO_PCR0  (OMAP_MCBSP1_BASE + 0x24)
-
-/* UART3 Registers Maping through MPU bus */
-#define OMAP_MPU_UART3_BASE     0xFFFB9800      /* UART3 through MPU bus */
-#define UART3_RHR               (OMAP_MPU_UART3_BASE + 0)
-#define UART3_THR               (OMAP_MPU_UART3_BASE + 0)
-#define UART3_DLL               (OMAP_MPU_UART3_BASE + 0)
-#define UART3_IER               (OMAP_MPU_UART3_BASE + 4)
-#define UART3_DLH               (OMAP_MPU_UART3_BASE + 4)
-#define UART3_IIR               (OMAP_MPU_UART3_BASE + 8)
-#define UART3_FCR               (OMAP_MPU_UART3_BASE + 8)
-#define UART3_EFR               (OMAP_MPU_UART3_BASE + 8)
-#define UART3_LCR               (OMAP_MPU_UART3_BASE + 0x0C)
-#define UART3_MCR               (OMAP_MPU_UART3_BASE + 0x10)
-#define UART3_XON1_ADDR1        (OMAP_MPU_UART3_BASE + 0x10)
-#define UART3_XON2_ADDR2        (OMAP_MPU_UART3_BASE + 0x14)
-#define UART3_LSR               (OMAP_MPU_UART3_BASE + 0x14)
-#define UART3_TCR               (OMAP_MPU_UART3_BASE + 0x18)
-#define UART3_MSR               (OMAP_MPU_UART3_BASE + 0x18)
-#define UART3_XOFF1             (OMAP_MPU_UART3_BASE + 0x18)
-#define UART3_XOFF2             (OMAP_MPU_UART3_BASE + 0x1C)
-#define UART3_SPR               (OMAP_MPU_UART3_BASE + 0x1C)
-#define UART3_TLR               (OMAP_MPU_UART3_BASE + 0x1C)
-#define UART3_MDR1              (OMAP_MPU_UART3_BASE + 0x20)
-#define UART3_MDR2              (OMAP_MPU_UART3_BASE + 0x24)
-#define UART3_SFLSR             (OMAP_MPU_UART3_BASE + 0x28)
-#define UART3_TXFLL             (OMAP_MPU_UART3_BASE + 0x28)
-#define UART3_RESUME            (OMAP_MPU_UART3_BASE + 0x2C)
-#define UART3_TXFLH             (OMAP_MPU_UART3_BASE + 0x2C)
-#define UART3_SFREGL            (OMAP_MPU_UART3_BASE + 0x30)
-#define UART3_RXFLL             (OMAP_MPU_UART3_BASE + 0x30)
-#define UART3_SFREGH            (OMAP_MPU_UART3_BASE + 0x34)
-#define UART3_RXFLH             (OMAP_MPU_UART3_BASE + 0x34)
-#define UART3_BLR               (OMAP_MPU_UART3_BASE + 0x38)
-#define UART3_ACREG             (OMAP_MPU_UART3_BASE + 0x3C)
-#define UART3_DIV16             (OMAP_MPU_UART3_BASE + 0x3C)
-#define UART3_SCR               (OMAP_MPU_UART3_BASE + 0x40)
-#define UART3_SSR               (OMAP_MPU_UART3_BASE + 0x44)
-#define UART3_EBLR              (OMAP_MPU_UART3_BASE + 0x48)
-#define UART3_OSC_12M_SEL       (OMAP_MPU_UART3_BASE + 0x4C)
-#define UART3_MVR               (OMAP_MPU_UART3_BASE + 0x50)
 
 #endif /*  __ASM_ARCH_OMAP_H3_H */
index 87e45d9..9229b2d 100644 (file)
@@ -71,17 +71,11 @@ unsigned char fpga_read(int reg);
 
 #endif /* CONFIG_ARCH_OMAP1510 */
 
-#if defined (CONFIG_ARCH_OMAP1610)
+#if defined (CONFIG_ARCH_OMAP16XX)
 
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
-#define OMAP1610_ETHR_BASE             0xE8000000
-#define OMAP1610_ETHR_SIZE             SZ_4K
-#define OMAP1610_ETHR_START            0x04000000
-
-/* Intel STRATA NOR flash at CS3 */
-#define OMAP1610_NOR_FLASH_BASE                0xD8000000
-#define OMAP1610_NOR_FLASH_SIZE                SZ_32M
-#define OMAP1610_NOR_FLASH_START       0x0C000000
+#define INNOVATOR1610_ETHR_START       0x04000000
+#define INNOVATOR1610_ETHR_SIZE                SZ_4K
 
 #endif /* CONFIG_ARCH_OMAP1610 */
 #endif /* __ASM_ARCH_OMAP_INNOVATOR_H */
index a241935..1cefd60 100644 (file)
 #define OMAP_TAG_CLOCK         0x4f01
 #define OMAP_TAG_MMC           0x4f02
 #define OMAP_TAG_UART          0x4f03
-#define OMAP_TAG_USB            0x4f04
+#define OMAP_TAG_USB           0x4f04
+#define OMAP_TAG_LCD           0x4f05
+#define OMAP_TAG_GPIO_SWITCH   0x4f06
+
+#define OMAP_TAG_BOOT_REASON    0x4f80
+#define OMAP_TAG_FLASH_PART    0x4f81
 
 struct omap_clock_config {
        /* 0 for 12 MHz, 1 for 13 MHz and 2 for 19.2 MHz */
@@ -26,8 +31,8 @@ struct omap_clock_config {
 
 struct omap_mmc_config {
        u8 mmc_blocks;
-       s8 mmc1_power_pin, mmc2_power_pin;
-       s8 mmc1_switch_pin, mmc2_switch_pin;
+       s16 mmc1_power_pin, mmc2_power_pin;
+       s16 mmc1_switch_pin, mmc2_switch_pin;
 };
 
 struct omap_uart_config {
@@ -63,6 +68,38 @@ struct omap_usb_config {
        u8              pins[3];
 };
 
+struct omap_lcd_config {
+       char panel_name[16];
+       char ctrl_name[16];
+};
+
+/* Cover:
+ *      high -> closed
+ *      low  -> open
+ * Connection:
+ *      high -> connected
+ *      low  -> disconnected
+ */
+#define OMAP_GPIO_SWITCH_TYPE_COVER            0x0000
+#define OMAP_GPIO_SWITCH_TYPE_CONNECTION       0x0001
+#define OMAP_GPIO_SWITCH_FLAG_INVERTED          0x0001
+struct omap_gpio_switch_config {
+       char name[12];
+       u16 gpio;
+       int flags:4;
+       int type:4;
+       int key_code:24; /* Linux key code */
+};
+
+struct omap_flash_part_config {
+       char part_table[0];
+};
+
+struct omap_boot_reason_config {
+       char reason_str[12];
+};
+
+
 struct omap_board_config_entry {
        u16 tag;
        u16 len;
@@ -74,10 +111,14 @@ struct omap_board_config_kernel {
        const void *data;
 };
 
-extern const void *__omap_get_config(u16 tag, size_t len);
+extern const void *__omap_get_config(u16 tag, size_t len, int nr);
 
 #define omap_get_config(tag, type) \
-       ((const type *) __omap_get_config((tag), sizeof(type)))
+       ((const type *) __omap_get_config((tag), sizeof(type), 0))
+#define omap_get_nr_config(tag, type, nr) \
+       ((const type *) __omap_get_config((tag), sizeof(type), (nr)))
+
+extern const void *omap_get_var_config(u16 tag, size_t *len);
 
 extern struct omap_board_config_kernel *omap_board_config;
 extern int omap_board_config_size;
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
index 6622ba3..1c8c9fc 100644 (file)
@@ -40,9 +40,9 @@
  * We don't actually have real ISA nor PCI buses, but there is so many
  * drivers out there that might just work if we fake them...
  */
-#define __io(a)                        (PCIO_BASE + (a))
-#define __mem_pci(a)           ((unsigned long)(a))
-#define __mem_isa(a)           ((unsigned long)(a))
+#define __io(a)                        ((void __iomem *)(PCIO_BASE + (a)))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           (a)
 
 /*
  * ----------------------------------------------------------------------------
index 7cf5774..1bae6b4 100644 (file)
 #define INT_730_TIMER32K       (22 + IH2_BASE)
 #define INT_730_MMC_SDIO       (23 + IH2_BASE)
 #define INT_730_UPLD           (24 + IH2_BASE)
-#define INT_730_RTC_TIMER      (25 + IH2_BASE)
-#define INT_730_RTC_ALARM      (26 + IH2_BASE)
 #define INT_730_USB_HHC_1      (27 + IH2_BASE)
 #define INT_730_USB_HHC_2      (28 + IH2_BASE)
 #define INT_730_USB_GENI       (29 + IH2_BASE)
 #define INT_730_DMA_CH15       (62 + IH2_BASE)
 #define INT_730_NAND           (63 + IH2_BASE)
 
-/* OMAP-730 differences */
-#ifdef CONFIG_ARCH_OMAP730
-#undef INT_IH2_IRQ
-#define INT_IH2_IRQ            INT_730_IH2_IRQ
-#undef INT_KEYBOARD
-#define INT_KEYBOARD           INT_730_MPUIO_KEYPAD
-#undef INT_UART1
-#define INT_UART1              INT_730_UART_MODEM_1
-#undef INT_UART2
-#define INT_UART2              INT_730_UART_MODEM_IRDA_2
-#undef INT_MPUIO
-#define INT_MPUIO              INT_730_MPUIO
-#undef INT_RTC_TIMER
-#define INT_RTC_TIMER          INT_730_RTC_TIMER
-#undef INT_RTC_ALARM
-#define INT_RTC_ALARM          INT_730_RTC_ALARM
-#endif
-
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
  * 16 MPUIO lines */
 #define OMAP_MAX_GPIO_LINES    192
@@ -260,7 +240,7 @@ extern void omap_init_irq(void);
 #include <asm/arch/hardware.h>
 
 #ifndef NR_IRQS
-#define NR_IRQS                 256
+#define NR_IRQS                 IH_BOARD_BASE
 #endif
 
 #endif
index 8e490e3..eb30325 100644 (file)
@@ -29,7 +29,7 @@
 #define OMAP730_MCBSP1_BASE    0xfffb1000
 #define OMAP730_MCBSP2_BASE    0xfffb1800
 
-#define OMAP1510_MCBSP1_BASE   0xe1011000
+#define OMAP1510_MCBSP1_BASE   0xe1011800
 #define OMAP1510_MCBSP2_BASE   0xfffb1000
 #define OMAP1510_MCBSP3_BASE   0xe1017000
 
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 */
index 5a3dfb6..b61ddb4 100644 (file)
@@ -28,8 +28,6 @@
 #if !defined(__ASM_ARCH_OMAP_TIMEX_H)
 #define __ASM_ARCH_OMAP_TIMEX_H
 
-#include <asm/arch/clocks.h>
-/* TC clock */
-#define CLOCK_TICK_RATE                ((OMAP_CK_MAX_RATE*1000000)/2)
+#define CLOCK_TICK_RATE                (HZ * 100000UL)
 
 #endif /* __ASM_ARCH_OMAP_TIMEX_H */
index d58fb7b..c3bdbe4 100644 (file)
@@ -12,8 +12,8 @@
  * We don't actually have real ISA nor PCI buses, but there is so many
  * drivers out there that might just work if we fake them...
  */
-#define __io(a)                        (a)
-#define __mem_pci(a)           ((unsigned long)(a))
-#define __mem_isa(a)           ((unsigned long)(a))
+#define __io(a)                        ((void __iomem *)(a))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           (a)
 
 #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
index 939aa6a..83a43e4 100644 (file)
@@ -250,6 +250,6 @@ DECLARE_IO(int,l,"")
 /*
  * 1:1 mapping for ioremapped regions.
  */
-#define __mem_pci(x)   ((unsigned long)(x))
+#define __mem_pci(x)   (x)
 
 #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 */
index 9cae382..c1019ef 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/include/asm-arm/arch-bast/dma.h
  *
- * Copyright (C) 2003 Simtec Electronics
- *  Ben Dooks <ben@simtec.co.uk>
+ * Copyright (C) 2003,2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
  *
  * Samsung S3C2410X DMA support
  *
  * Changelog:
  *  ??-May-2003 BJD   Created file
  *  ??-Jun-2003 BJD   Added more dma functionality to go with arch
+ *  10-Nov-2004 BJD   Added sys_device support
 */
 
-
 #ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H __FILE__
 
 #include <linux/config.h>
+#include <linux/sysdev.h>
 #include "hardware.h"
 
 
@@ -198,9 +199,9 @@ struct s3c2410_dma_chan_s {
        unsigned int           flags;        /* channel flags */
 
        /* channel's hardware position and configuration */
-       unsigned long          regs;         /* channels registers */
+       void __iomem           *regs;        /* channels registers */
+       void __iomem           *addr_reg;    /* data address register */
        unsigned int           irq;          /* channel irq */
-       unsigned long          addr_reg;     /* data address register */
        unsigned long          dcon;         /* default value of DCON */
 
        /* driver handles */
@@ -215,6 +216,9 @@ struct s3c2410_dma_chan_s {
        s3c2410_dma_buf_t      *curr;        /* current dma buffer */
        s3c2410_dma_buf_t      *next;        /* next buffer to load */
        s3c2410_dma_buf_t      *end;         /* end of queue */
+
+       /* system device */
+       struct sys_device       dev;
 };
 
 /* the currently allocated channel information */
@@ -296,18 +300,46 @@ extern int s3c2410_dma_set_buffdone_fn(dmach_t, s3c2410_dma_cbfn_t rtn);
 #define S3C2410_DMA_DCDST       (0x1C)
 #define S3C2410_DMA_DMASKTRIG   (0x20)
 
+#define S3C2410_DISRCC_INC     (1<<0)
+#define S3C2410_DISRCC_APB     (1<<1)
+
 #define S3C2410_DMASKTRIG_STOP   (1<<2)
 #define S3C2410_DMASKTRIG_ON     (1<<1)
 #define S3C2410_DMASKTRIG_SWTRIG (1<<0)
 
-#define S3C2410_DCOM_DEMAND     (0<<31)
+#define S3C2410_DCON_DEMAND     (0<<31)
 #define S3C2410_DCON_HANDSHAKE  (1<<31)
 #define S3C2410_DCON_SYNC_PCLK  (0<<30)
 #define S3C2410_DCON_SYNC_HCLK  (1<<30)
 
 #define S3C2410_DCON_INTREQ     (1<<29)
 
+#define S3C2410_DCON_CH0_XDREQ0        (0<<24)
+#define S3C2410_DCON_CH0_UART0 (1<<24)
+#define S3C2410_DCON_CH0_SDI   (2<<24)
+#define S3C2410_DCON_CH0_TIMER (3<<24)
+#define S3C2410_DCON_CH0_USBEP1        (4<<24)
+
+#define S3C2410_DCON_CH1_XDREQ1        (0<<24)
+#define S3C2410_DCON_CH1_UART1 (1<<24)
+#define S3C2410_DCON_CH1_I2SSDI        (2<<24)
+#define S3C2410_DCON_CH1_SPI   (3<<24)
+#define S3C2410_DCON_CH1_USBEP2        (4<<24)
+
+#define S3C2410_DCON_CH2_I2SSDO        (0<<24)
+#define S3C2410_DCON_CH2_I2SSDI        (1<<24)
+#define S3C2410_DCON_CH2_SDI   (2<<24)
+#define S3C2410_DCON_CH2_TIMER (3<<24)
+#define S3C2410_DCON_CH2_USBEP3        (4<<24)
+
+#define S3C2410_DCON_CH3_UART2 (0<<24)
+#define S3C2410_DCON_CH3_SDI   (1<<24)
+#define S3C2410_DCON_CH3_SPI   (2<<24)
+#define S3C2410_DCON_CH3_TIMER (3<<24)
+#define S3C2410_DCON_CH3_USBEP4        (4<<24)
+
 #define S3C2410_DCON_SRCSHIFT   (24)
+#define S3C2410_DCON_SRCMASK   (7<<24)
 
 #define S3C2410_DCON_BYTE       (0<<20)
 #define S3C2410_DCON_HALFWORD   (1<<20)
@@ -317,4 +349,20 @@ extern int s3c2410_dma_set_buffdone_fn(dmach_t, s3c2410_dma_cbfn_t rtn);
 #define S3C2410_DCON_NORELOAD   (1<<22)
 #define S3C2410_DCON_HWTRIG     (1<<23)
 
+#ifdef CONFIG_CPU_S3C2440
+#define S3C2440_DIDSTC_CHKINT  (1<<2)
+
+#define S3C2440_DCON_CH0_I2SSDO        (5<<24)
+#define S3C2440_DCON_CH0_PCMIN (6<<24)
+
+#define S3C2440_DCON_CH1_PCMOUT        (5<<24)
+#define S3C2440_DCON_CH1_SDI   (6<<24)
+
+#define S3C2440_DCON_CH2_PCMIN (5<<24)
+#define S3C2440_DCON_CH2_MICIN (6<<24)
+
+#define S3C2440_DCON_CH3_MICIN (5<<24)
+#define S3C2440_DCON_CH3_PCMOUT        (6<<24)
+#endif
+
 #endif /* __ASM_ARCH_DMA_H */
index 5b58f2a..7b489fd 100644 (file)
@@ -16,6 +16,7 @@
  *  12-Mar-2004 BJD  Fixed include protection, fixed type of clock vars
  *  14-Sep-2004 BJD  Added misccr and getpin to gpio
  *  01-Oct-2004 BJD  Added the new gpio functions
+ *  16-Oct-2004 BJD  Removed the clock variables
 */
 
 #ifndef __ASM_ARCH_HARDWARE_H
 
 #ifndef __ASSEMBLY__
 
-/* processor clock settings, in Hz */
-extern unsigned long s3c2410_pclk;
-extern unsigned long s3c2410_hclk;
-extern unsigned long s3c2410_fclk;
-
 /* external functions for GPIO support
  *
  * These allow various different clients to access the same GPIO
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 */
index 0da1ec7..a023b04 100644 (file)
 
 #ifdef CONFIG_CPU_S3C2440
 
-#define S3C2440_DSC0      S3C2410_GPIOREG(0xc0)
-#define S3C2440_DSC1      S3C2410_GPIOREG(0xc4)
+#define S3C2440_DSC0      S3C2410_GPIOREG(0xc4)
+#define S3C2440_DSC1      S3C2410_GPIOREG(0xc8)
 
 #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_DISABLE   (1<<31)
 
 #define S3C2440_DSC0_ADDR       (S3C2440_SELECT_DSC0 | 8)
 #define S3C2440_DSC0_ADDR_12mA  (0<<8)
 #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_SCK1       (S3C2440_SELECT_DSC1 | 28)
+#define S3C2440_DSC1_SCK1_12mA  (0<<28)
+#define S3C2440_DSC1_SCK1_10mA  (1<<28)
+#define S3C2440_DSC1_SCK1_8mA   (2<<28)
+#define S3C2440_DSC1_SCK1_6mA   (3<<28)
+#define S3C2440_DSC1_SCK1_MASK  (3<<28)
+
+#define S3C2440_DSC1_SCK0       (S3C2440_SELECT_DSC1 | 26)
+#define S3C2440_DSC1_SCK0_12mA  (0<<26)
+#define S3C2440_DSC1_SCK0_10mA  (1<<26)
+#define S3C2440_DSC1_SCK0_8mA   (2<<26)
+#define S3C2440_DSC1_SCK0_6mA   (3<<26)
+#define S3C2440_DSC1_SCK0_MASK  (3<<26)
 
 #define S3C2440_DSC1_SCKE       (S3C2440_SELECT_DSC1 | 24)
 #define S3C2440_DSC1_SCKE_10mA  (0<<24)
index 05eb116..07c17f9 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/include/asm/hardware/s3c2410/
+/* linux/include/asm/hardware/s3c2410/regs-gpio.h
  *
  * Copyright (c) 2003,2004 Simtec Electronics <linux@simtec.co.uk>
  *                        http://www.simtec.co.uk/products/SWLINUX/
@@ -15,6 +15,9 @@
  *    12-03-2004     BJD     Updated include protection
  *    20-07-2004     BJD     Added GPIO pin numbers, added Port A definitions
  *    04-10-2004     BJD     Fixed number of bugs, added EXT IRQ filter defs
+ *    17-10-2004     BJD     Added GSTATUS1 register definitions
+ *    18-11-2004     BJD     Fixed definitions of GPE3, GPE4, GPE5 and GPE6
+ *    18-11-2004     BJD     Added S3C2440 AC97 controls
 */
 
 
 #define S3C2410_GPE3_INP       (0x00 << 6)
 #define S3C2410_GPE3_OUTP      (0x01 << 6)
 #define S3C2410_GPE3_I2SSDI    (0x02 << 6)
+#define S3C2410_GPE3_nSS0      (0x03 << 6)
 #define S3C2410_GPE3_MASK      (0x03 << 6)
 
 #define S3C2410_GPE4           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 4)
 #define S3C2410_GPE4_INP       (0x00 << 8)
 #define S3C2410_GPE4_OUTP      (0x01 << 8)
 #define S3C2410_GPE4_I2SSDO    (0x02 << 8)
+#define S3C2410_GPE4_I2SSDI    (0x03 << 8)
 #define S3C2410_GPE4_MASK      (0x03 << 8)
 
 #define S3C2410_GPE5           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 5)
 #define S3C2410_GPE6           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 6)
 #define S3C2410_GPE6_INP       (0x00 << 12)
 #define S3C2410_GPE6_OUTP      (0x01 << 12)
-#define S3C2410_GPE6_SDCLK     (0x02 << 12)
+#define S3C2410_GPE6_SDCMD     (0x02 << 12)
 
 #define S3C2410_GPE7           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 7)
 #define S3C2410_GPE7_INP       (0x00 << 14)
 #define S3C2410_GPE7_OUTP      (0x01 << 14)
-#define S3C2410_GPE7_SDCMD     (0x02 << 14)
+#define S3C2410_GPE7_SDDAT0    (0x02 << 14)
 
 #define S3C2410_GPE8           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 8)
 #define S3C2410_GPE8_INP       (0x00 << 16)
 #define S3C2410_GPE15_IICSDA   (0x02 << 30)
 #define S3C2410_GPE15_MASK     (0x03 << 30)
 
+#define S3C2440_GPE0_ACSYNC    (0x03 << 0)
+#define S3C2440_GPE1_ACBITCLK  (0x03 << 2)
+#define S3C2440_GPE2_ACRESET   (0x03 << 4)
+#define S3C2440_GPE3_ACIN      (0x03 << 6)
+#define S3C2440_GPE4_ACOUT     (0x03 << 8)
+
 #define S3C2410_GPE_PUPDIS(x)  (1<<(x))
 
 /* Port F consists of 8 GPIO/Special function
 #define S3C2410_GSTATUS0_RnB      (1<<1)
 #define S3C2410_GSTATUS0_nBATTFLT  (1<<0)
 
+#define S3C2410_GSTATUS1_IDMASK           (0xffff0000)
+#define S3C2410_GSTATUS1_2410     (0x32410000)
+#define S3C2410_GSTATUS1_2440     (0x32440000)
+
 #define S3C2410_GSTATUS2_WTRESET   (1<<2)
-#define S3C2410_GSTATUs2_OFFRESET  (1<<1)
+#define S3C2410_GSTATUS2_OFFRESET  (1<<1)
 #define S3C2410_GSTATUS2_PONRESET  (1<<0)
 
 #endif /* __ASM_ARCH_REGS_GPIO_H */
index 028ab20..fed3288 100644 (file)
  *
  *  Changelog:
  *     03-Oct-2004  BJD  Initial include for Linux
+ *     08-Nov-2004  BJD  Added S3C2440 filter register
 */
 
-#ifndef __ASM_ARCH_IIC_H
-#define __ASM_ARCH_IIC_H __FILE__
+#ifndef __ASM_ARCH_REGS_IIC_H
+#define __ASM_ARCH_REGS_IIC_H __FILE__
 
 /* see s3c2410x user guide, v1.1, section 9 (p447) for more info */
 
@@ -24,6 +25,7 @@
 #define S3C2410_IICSTAT   S3C2410_IICREG(0x04)
 #define S3C2410_IICADD    S3C2410_IICREG(0x08)
 #define S3C2410_IICDS     S3C2410_IICREG(0x0C)
+#define S3C2440_IICLC    S3C2410_IICREG(0x10)
 
 #define S3C2410_IICCON_ACKEN           (1<<7)
 #define S3C2410_IICCON_TXDIV_16                (0<<6)
 #define S3C2410_IICSTAT_ADDR0          (1<<1)
 #define S3C2410_IICSTAT_LASTBIT                (1<<0)
 
-#endif /* __ASM_ARCH_IIC_H */
+#define S3C2410_IICLC_SDA_DELAY0       (0 << 0)
+#define S3C2410_IICLC_SDA_DELAY5       (1 << 0)
+#define S3C2410_IICLC_SDA_DELAY10      (2 << 0)
+#define S3C2410_IICLC_SDA_DELAY15      (3 << 0)
+#define S3C2410_IICLC_SDA_DELAY_MASK   (3 << 0)
+
+#define S3C2410_IICLC_FILTER_ON                (1<<2)
+
+#endif /* __ASM_ARCH_REGS_IIC_H */
index e0dad35..eda2a7b 100644 (file)
@@ -29,7 +29,7 @@
 #define S3C2410_LCDCON5            S3C2410_LCDREG(0x10)
 
 #define S3C2410_LCDCON1_CLKVAL(x)  ((x) << 8)
-#define S3C2410_LCDCON1_MMODE     (1<<6)
+#define S3C2410_LCDCON1_MMODE     (1<<7)
 #define S3C2410_LCDCON1_DSCAN4    (0<<5)
 #define S3C2410_LCDCON1_STN4      (1<<5)
 #define S3C2410_LCDCON1_STN8      (2<<5)
 #define S3C2410_LCDCON1_TFT16BPP   (12<<1)
 #define S3C2410_LCDCON1_TFT24BPP   (13<<1)
 
-#define S3C2410_LCDCON1_ENVDI     (1)
+#define S3C2410_LCDCON1_ENVID     (1)
 
 #define S3C2410_LCDCON2_VBPD(x)            ((x) << 24)
 #define S3C2410_LCDCON2_LINEVAL(x)  ((x) << 14)
 #define S3C2410_LCDCON2_VFPD(x)            ((x) << 6)
 #define S3C2410_LCDCON2_VSPW(x)            ((x) << 0)
 
-#define S3C2410_LCDCON3_HBPD(x)            ((x) << 25)
-#define S3C2410_LCDCON3_WDLY(x)            ((x) << 25)
+#define S3C2410_LCDCON3_HBPD(x)            ((x) << 19)
+#define S3C2410_LCDCON3_WDLY(x)            ((x) << 19)
 #define S3C2410_LCDCON3_HOZVAL(x)   ((x) << 8)
 #define S3C2410_LCDCON3_HFPD(x)            ((x) << 0)
 #define S3C2410_LCDCON3_LINEBLANK(x)((x) << 0)
 #define S3C2410_LCDSADDR2   S3C2410_LCDREG(0x18)
 #define S3C2410_LCDSADDR3   S3C2410_LCDREG(0x1C)
 
+#define S3C2410_LCDBANK(x)     ((x) << 21)
+#define S3C2410_LCDBASEU(x)    (x)
+
+#define S3C2410_OFFSIZE(x)     ((x) << 11)
+#define S3C2410_PAGEWIDTH(x)   (x)
+
 /* colour lookup and miscellaneous controls */
 
 #define S3C2410_REDLUT    S3C2410_LCDREG(0x20)
index bbe2b67..408cf04 100644 (file)
@@ -21,6 +21,8 @@
 
 #define S3C2410_RTCCON       S3C2410_RTCREG(0x40)
 #define S3C2410_RTCCON_RTCEN  (1<<0)
+#define S3C2410_RTCCON_CLKSEL (1<<1)
+#define S3C2410_RTCCON_CNTSEL (1<<2)
 #define S3C2410_RTCCON_CLKRST (1<<3)
 
 #define S3C2410_TICNT        S3C2410_RTCREG(0x44)
index fd688ad..ca9a26f 100644 (file)
@@ -11,6 +11,8 @@
  *
  *  Changelog:
  *    18-Aug-2004 Ben Dooks      Created initial file
+ *    29-Nov-2004 Koen Martens   Added some missing defines, fixed duplicates
+ *    29-Nov-2004 Ben Dooks     Updated Koen's patch
 */
 
 #ifndef __ASM_ARM_REGS_SDI
 #define S3C2410_SDIDCON_WIDEBUS       (1<<16)
 #define S3C2410_SDIDCON_DMAEN         (1<<15)
 #define S3C2410_SDIDCON_STOP          (1<<14)
+#define S3C2410_SDIDCON_DATMODE              (3<<12)
+#define S3C2410_SDIDCON_BLKNUM        (0x7ff)
 
-#define S3C2410_SDIDCON_XFER_MASK     (3<<12)
+/* constants for S3C2410_SDIDCON_DATMODE */
 #define S3C2410_SDIDCON_XFER_READY    (0<<12)
 #define S3C2410_SDIDCON_XFER_CHKSTART (1<<12)
 #define S3C2410_SDIDCON_XFER_RXSTART  (2<<12)
 
 #define S3C2410_SDIDSTA_RDYWAITREQ    (1<<10)
 #define S3C2410_SDIDSTA_SDIOIRQDETECT (1<<9)
-#define S3C2410_SDIDSTA_FIFOFAIL      (1<<8)
+#define S3C2410_SDIDSTA_FIFOFAIL      (1<<8)   /* reserved on 2440 */
 #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_SBITERR       (1<<2)   /* reserved on 2410a/2440 */
 #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_TFDET          (1<<13)
+#define S3C2410_SDIFSTA_RFDET          (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_RFLAST         (1<<9)
+#define S3C2410_SDIFSTA_RFFULL         (1<<8)
+#define S3C2410_SDIFSTA_RFHALF         (1<<7)
 #define S3C2410_SDIFSTA_COUNTMASK      (0x7f)
 
 #define S3C2410_SDIIMSK_RESPONSECRC    (1<<17)
 #define S3C2410_SDIIMSK_DATATIMEOUT    (1<<8)
 #define S3C2410_SDIIMSK_DATAFINISH     (1<<7)
 #define S3C2410_SDIIMSK_BUSYFINISH     (1<<6)
+#define S3C2410_SDIIMSK_SBITERR        (1<<5)  /* reserved 2440/2410a */
 #define S3C2410_SDIIMSK_TXFIFOHALF     (1<<4)
 #define S3C2410_SDIIMSK_TXFIFOEMPTY    (1<<3)
 #define S3C2410_SDIIMSK_RXFIFOLAST     (1<<2)
index aee2805..ad550bb 100644 (file)
@@ -8,8 +8,9 @@
  * the License, or (at your option) any later version.
  *
  *  Changelog:
- *    01-08-2004       initial creation
- *    12-09-2004       cleanup for submission
+ *    01-08-2004       Initial creation
+ *    12-09-2004       Cleanup for submission
+ *    24-10-2004       Fixed S3C2410_UDC_MAXP_REG definition
  */
 
 #ifndef __ASM_ARCH_REGS_UDC_H
@@ -68,7 +69,7 @@
 
 /* indexed registers */
 
-#define S3C2410_UDC_MAXP_REG           S3C2410_USBDREG(0x018c)
+#define S3C2410_UDC_MAXP_REG           S3C2410_USBDREG(0x0180)
 
 #define S3C2410_UDC_EP0_CSR_REG                S3C2410_USBDREG(0x0184)
 
index f375d93..b09d510 100644 (file)
@@ -38,6 +38,7 @@
 #define S3C2410_WTCON_DIV128  (3<<3)
 
 #define S3C2410_WTCON_PRESCALE(x) ((x) << 8)
+#define S3C2410_WTCON_PRESCALE_MASK (0xff00)
 
 #endif /* __ASM_ARCH_REGS_WATCHDOG_H */
 
index 1322cec..2760cf5 100644 (file)
  *  14-May-2003 BJD  Removed idle to aid debugging
  *  12-Jun-2003 BJD  Added reset via watchdog
  *  04-Sep-2003 BJD  Moved to v2.6
+ *  28-Oct-2004 BJD  Added over-ride for idle, and fixed reset panic()
  */
 
 #include <asm/hardware.h>
 #include <asm/io.h>
 
 #include <asm/arch/map.h>
+#include <asm/arch/idle.h>
 
 #include <asm/arch/regs-watchdog.h>
 #include <asm/arch/regs-clock.h>
 
-extern void printascii(const char *);
+void (*s3c24xx_idle)(void);
 
-void
-arch_idle(void)
+void s3c24xx_default_idle(void)
 {
-       //unsigned long reg = S3C2410_CLKCON;
-
-       //printascii("arch_idle:\n");
+       unsigned long reg = S3C2410_CLKCON;
+       unsigned long tmp;
+       int i;
 
        /* idle the system by using the idle mode which will wait for an
         * interrupt to happen before restarting the system.
         */
 
-       /* going into idle state upsets the jtag, so don't do it
-        * at the moment */
+       /* Warning: going into idle state upsets jtag scanning */
 
-#if 0
        __raw_writel(__raw_readl(reg) | (1<<2), reg);
 
        /* the samsung port seems to do a loop and then unset idle.. */
        for (i = 0; i < 50; i++) {
-               tmp = __raw_readl(reg); /* ensure loop not optimised out */
+               tmp += __raw_readl(reg); /* ensure loop not optimised out */
        }
 
-       //printascii("arch_idle: done\n");
+       /* this bit is not cleared on re-start... */
 
        __raw_writel(__raw_readl(reg) & ~(1<<2), reg);
-#endif
+}
+
+static void arch_idle(void)
+{
+       if (s3c24xx_idle != NULL)
+               (s3c24xx_idle)();
+       else
+               s3c24xx_default_idle();
 }
 
 
@@ -77,7 +83,7 @@ arch_reset(char mode)
        /* wait for reset to assert... */
        mdelay(5000);
 
-       panic("Watchdog reset failed to assert reset\n");
+       printk(KERN_ERR "Watchdog reset failed to assert reset\n");
 
        /* we'll take a jump through zero as a poor second */
        cpu_reset(0);
index fffde7d..44aa0dc 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/include/asm-arm/arch-s3c2410/timex.h
  *
- * (c) 2003 Simtec Electronics
+ * (c) 2003,2004 Simtec Electronics
  *  Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 - time parameters
@@ -12,6 +12,7 @@
  * Changelog:
  *  02-Sep-2003 BJD  Created file
  *  05-Jan-2004 BJD  Updated for Linux 2.6.0
+ *  22-Nov-2004 BJD  Fixed CLOCK_TICK_RATE
 */
 
 #ifndef __ASM_ARCH_TIMEX_H
@@ -26,8 +27,8 @@ extern int s3c2410_clock_tick_rate;
 #define CLOCK_TICK_RATE (s3c2410_clock_tick_rate)
 #endif
 
-/* currently, the BAST uses 24MHz as a base clock rate */
-#define CLOCK_TICK_RATE 24000000
+/* currently, the BAST uses 12MHz as a base clock rate */
+#define CLOCK_TICK_RATE 12000000
 
 
 #endif /* __ASM_ARCH_TIMEX_H */
index 023f22b..fa240af 100644 (file)
  *  22-May-2003 BJD  Created
  *  08-Sep-2003 BJD  Moved to linux v2.6
  *  12-Mar-2004 BJD  Updated header protection
+ *  12-Oct-2004 BJD  Take account of debug uart configuration
+ *  15-Nov-2004 BJD  Fixed uart configuration
 */
 
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H
 
+#include <linux/config.h>
+
 /* defines for UART registers */
 #include "asm/arch/regs-serial.h"
+#include "asm/arch/regs-gpio.h"
 
 #include <asm/arch/map.h>
 
+/* working in physical space... */
+#undef S3C2410_GPIOREG
+#define S3C2410_GPIOREG(x) ((S3C2410_PA_GPIO + (x)))
+
 /* how many bytes we allow into the FIFO at a time in FIFO mode */
 #define FIFO_MAX        (14)
 
-#if 1
-#define uart_base S3C2410_PA_UART
-#else
-static unsigned int uart_base = S3C2410_PA_UART;
-#endif
+#define uart_base S3C2410_PA_UART + (0x4000*CONFIG_S3C2410_LOWLEVEL_UART_PORT)
 
 static __inline__ void
 uart_wr(unsigned int reg, unsigned int val)
@@ -74,6 +79,10 @@ arch_decomp_setup(void)
 static void
 putc(char ch)
 {
+       int cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1);
+
+       cpuid &= S3C2410_GSTATUS1_IDMASK;
+
        if (ch == '\n')
                putc('\r');    /* expand newline to \r\n */
 
@@ -82,8 +91,14 @@ putc(char ch)
 
                while (1) {
                        level = uart_rd(S3C2410_UFSTAT);
-                       level &= S3C2410_UFSTAT_TXMASK;
-                       level >>= S3C2410_UFSTAT_TXSHIFT;
+
+                       if (cpuid == S3C2410_GSTATUS1_2440) {
+                               level &= S3C2440_UFSTAT_TXMASK;
+                               level >>= S3C2440_UFSTAT_TXSHIFT;
+                       } else {
+                               level &= S3C2410_UFSTAT_TXMASK;
+                               level >>= S3C2410_UFSTAT_TXSHIFT;
+                       }
 
                        if (level < FIFO_MAX)
                                break;
@@ -92,7 +107,7 @@ putc(char ch)
        } else {
                /* not using fifos */
 
-               while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE) != S3C2410_UTRSTAT_TXFE);
+               while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE);
        }
 
        /* write byte to transmission register */
index bc44296..2153538 100644 (file)
@@ -14,6 +14,8 @@
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 
+#error "This code is broken and needs update to match with current ide support"
+
 
 /*
  * Set up a hw structure for a specified data port, control port and IRQ.
@@ -47,10 +49,6 @@ static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
                *irq = 0;
 }
 
-#ifdef CONFIG_SA1100_TRIZEPS
-#include <asm/arch/trizeps.h>
-#endif
-
 /*
  * This registers the standard ports for this architecture with the IDE
  * driver.
@@ -58,55 +56,7 @@ static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
 static __inline__ void
 ide_init_default_hwifs(void)
 {
-    if( machine_is_empeg() ){
-#ifdef CONFIG_SA1100_EMPEG
-       hw_regs_t hw;
-
-       /* First, do the SA1100 setup */
-
-       /* PCMCIA IO space */
-       MECR=0x21062106;
-
-        /* Issue 3 is much neater than issue 2 */
-       GPDR&=~(EMPEG_IDE1IRQ|EMPEG_IDE2IRQ);
-
-       /* Interrupts on rising edge: lines are inverted before they get to
-           the SA */
-       set_GPIO_IRQ_edge( (EMPEG_IDE1IRQ|EMPEG_IDE2IRQ), GPIO_FALLING_EDGE );
-
-       /* Take hard drives out of reset */
-       GPSR=(EMPEG_IDERESET);
-
-       /* Sonja and her successors have two IDE ports. */
-       /* MAC 23/4/1999, swap these round so that the left hand
-          hard disk is hda when viewed from the front. This
-          doesn't match the silkscreen however. */
-       ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x40, PCMCIA_IO_0_BASE + 0x78, NULL);
-       hw.irq = EMPEG_IRQ_IDE2;
-       ide_register_hw(&hw);
-       ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x00, PCMCIA_IO_0_BASE + 0x38, NULL);
-       hw.irq = ,EMPEG_IRQ_IDE1;
-       ide_register_hw(&hw);
-#endif
-    }
-
-    else if( machine_is_victor() ){
-#ifdef CONFIG_SA1100_VICTOR
-       hw_regs_t hw;
-
-       /* Enable appropriate GPIOs as interrupt lines */
-       GPDR &= ~GPIO_GPIO7;
-       set_GPIO_IRQ_edge( GPIO_GPIO7, GPIO_RISING_EDGE );
-
-       /* set the pcmcia interface timing */
-       MECR = 0x00060006;
-
-       ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x1f0, PCMCIA_IO_0_BASE + 0x3f6, NULL);
-       hw.irq = IRQ_GPIO7;
-       ide_register_hw(&hw);
-#endif
-    }
-    else if (machine_is_lart()) {
+    if (machine_is_lart()) {
 #ifdef CONFIG_SA1100_LART
         hw_regs_t hw;
 
@@ -121,25 +71,6 @@ ide_init_default_hwifs(void)
        ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x0000, PCMCIA_IO_0_BASE + 0x1000, NULL);
         hw.irq = LART_IRQ_IDE;
         ide_register_hw(&hw);
-#endif
-    }
-    else if( machine_is_trizeps() ){
-#ifdef CONFIG_SA1100_TRIZEPS
-       hw_regs_t hw;
-
-       /* Enable appropriate GPIOs as interrupt lines */
-       GPDR &= ~GPIO_GPIO(TRIZEPS_IRQ_IDE);
-       set_irq_type( TRIZEPS_IRQ_IDE, IRQT_RISING );
-
-       /* set the pcmcia interface timing */
-       //MECR = 0x00060006; // Done on trizeps init
-
-       /* Take hard drives out of reset */
-       GPSR = GPIO_GPIO(TRIZEPS_IRQ_IDE);
-
-       ide_init_hwif_ports(&hw, TRIZEPS_IDE_CS0 + 0, TRIZEPS_IDE_CS1 + 6, NULL);
-       hw.irq = TRIZEPS_IRQ_IDE;
-       ide_register_hw(&hw, NULL);
 #endif
     }
 }
index c7dea80..7d969ff 100644 (file)
@@ -16,8 +16,8 @@
  * We don't actually have real ISA nor PCI buses, but there is so many 
  * drivers out there that might just work if we fake them...
  */
-#define __io(a)                        (PCIO_BASE + (a))
-#define __mem_pci(a)           ((unsigned long)(a))
-#define __mem_isa(a)           ((unsigned long)(a))
+#define __io(a)                        ((void __iomem *)(PCIO_BASE + (a)))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           (a)
 
 #endif
index c0bbe24..6f52118 100644 (file)
@@ -10,13 +10,6 @@ static inline void arch_idle(void)
        cpu_do_idle();
 }
 
-#ifdef CONFIG_SA1100_VICTOR
-
-/* power off unconditionally */
-#define arch_reset(x) machine_power_off()
-
-#else
-
 static inline void arch_reset(char mode)
 {
        if (mode == 's') {
@@ -27,5 +20,3 @@ static inline void arch_reset(char mode)
                RSRR = RSRR_SWR;
        }
 }
-
-#endif
index 82aa1a3..837be9b 100644 (file)
@@ -10,4 +10,3 @@
  * SA1100 timer
  */
 #define CLOCK_TICK_RATE                3686400
-#define CLOCK_TICK_FACTOR      80
index 61abd02..1e7f26b 100644 (file)
@@ -170,7 +170,7 @@ DECLARE_IO(long,l,"")
        addr;                                                                   \
 })
 
-#define __mem_pci(addr) addr
+#define __mem_pci(addr) (addr)
 
 #define inb(p)         (__builtin_constant_p((p)) ? __inbc(p)    : __inb(p))
 #define inw(p)         (__builtin_constant_p((p)) ? __inwc(p)    : __inw(p))
index 535b1f0..d5fb4a2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/arch-versatile/hardware.h
  *
- *  This file contains the hardware definitions of the Versatile PB board.
+ *  This file contains the hardware definitions of the Versatile boards.
  *
  *  Copyright (C) 2003 ARM Limited.
  *
index 542bc6b..dbb7158 100644 (file)
@@ -22,8 +22,8 @@
 
 #define IO_SPACE_LIMIT 0xffff
 
-#define __io(a)                        ((a))
-#define __mem_pci(a)           ((unsigned long)(a))
-#define __mem_isa(a)           ((unsigned long)(a))
+#define __io(a)                        ((void __iomem *)(a))
+#define __mem_pci(a)           (a)
+#define __mem_isa(a)           (a)
 
 #endif
index 68be3f0..2598d1f 100644 (file)
@@ -47,7 +47,7 @@
 
 
 /* ------------------------------------------------------------------------
- *  Versatile PB Registers
+ *  Versatile Registers
  * ------------------------------------------------------------------------
  * 
  */
 #define VERSATILE_SYS_SW_OFFSET               0x04
 #define VERSATILE_SYS_LED_OFFSET              0x08
 #define VERSATILE_SYS_OSC0_OFFSET             0x0C
+
+#if defined(CONFIG_ARCH_VERSATILE_PB)
 #define VERSATILE_SYS_OSC1_OFFSET             0x10
 #define VERSATILE_SYS_OSC2_OFFSET             0x14
 #define VERSATILE_SYS_OSC3_OFFSET             0x18
 #define VERSATILE_SYS_OSC4_OFFSET             0x1C
+#elif defined(CONFIG_MACH_VERSATILE_AB)
+#define VERSATILE_SYS_OSC1_OFFSET             0x1C
+#endif
+
 #define VERSATILE_SYS_LOCK_OFFSET             0x20
 #define VERSATILE_SYS_100HZ_OFFSET            0x24
 #define VERSATILE_SYS_CFGDATA1_OFFSET         0x28
 #define VERSATILE_SYS_LED                     (VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET)
 #define VERSATILE_SYS_OSC0                    (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC0_OFFSET)
 #define VERSATILE_SYS_OSC1                    (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC1_OFFSET)
+
+#if defined(CONFIG_ARCH_VERSATILE_PB)
 #define VERSATILE_SYS_OSC2                    (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC2_OFFSET)
 #define VERSATILE_SYS_OSC3                    (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC3_OFFSET)
 #define VERSATILE_SYS_OSC4                    (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC4_OFFSET)
+#endif
+
 #define VERSATILE_SYS_LOCK                    (VERSATILE_SYS_BASE + VERSATILE_SYS_LOCK_OFFSET)
 #define VERSATILE_SYS_100HZ                   (VERSATILE_SYS_BASE + VERSATILE_SYS_100HZ_OFFSET)
 #define VERSATILE_SYS_CFGDATA1                (VERSATILE_SYS_BASE + VERSATILE_SYS_CFGDATA1_OFFSET)
 
 
 /* ------------------------------------------------------------------------
- *  Versatile PB control registers
+ *  Versatile control registers
  * ------------------------------------------------------------------------
  */
 
 #define VERSATILE_SSP_BASE             0x101F4000      /* Synchronous Serial Port */
 
 #define VERSATILE_SSMC_BASE            0x20000000      /* SSMC */
+#define VERSATILE_IB2_BASE             0x24000000      /* IB2 module */
 #define VERSATILE_MBX_BASE             0x40000000      /* MBX */
 #define VERSATILE_PCI_BASE             0x41000000      /* PCI Interface */
 #define VERSATILE_SDRAM67_BASE         0x70000000      /* SDRAM banks 6 and 7 */
 
 
 /* ------------------------------------------------------------------------
- *  Versatile PB Interrupt Controller - control registers
+ *  Versatile Interrupt Controller - control registers
  * ------------------------------------------------------------------------
  * 
  *  Offsets from interrupt controller base 
 #define VERSATILE_CSR_BASE             0x10000000
 #define VERSATILE_CSR_SIZE             0x10000000
 
+#ifdef CONFIG_MACH_VERSATILE_AB
+/*
+ * IB2 Versatile/AB expansion board definitions
+ */
+#define VERSATILE_IB2_CAMERA_BANK      0x24000000
+#define VERSATILE_IB2_KBD_DATAREG      0x25000000
+#define VERSATILE_IB2_IER              0x26000000      /* for VICINTSOURCE27 */
+#define VERSATILE_IB2_CTRL             0x27000000
+#define VERSATILE_IB2_STAT             0x27000004
+#endif
+
 #endif
 
 /*     END */
index 61da0c6..38fd04f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/arch-versatile/timex.h
  *
- *  Versatile PB architecture timex specifications
+ *  Versatile architecture timex specifications
  *
  *  Copyright (C) 2003 ARM Limited
  *
index 994e0ae..ce923ee 100644 (file)
@@ -342,7 +342,7 @@ static inline unsigned long __ffs(unsigned long word)
  * the clz instruction for much better code efficiency.
  */
 
-extern __inline__ int generic_fls(int x);
+static __inline__ int generic_fls(int x);
 #define fls(x) \
        ( __builtin_constant_p(x) ? generic_fls(x) : \
          ({ int __r; asm("clz\t%0, %1" : "=r"(__r) : "r"(x) : "cc"); 32-__r; }) )
index 4ebcea0..1704360 100644 (file)
@@ -1,14 +1,22 @@
-#ifndef __ASM_ARM_DELAY_H
-#define __ASM_ARM_DELAY_H
-
 /*
- * Copyright (C) 1995 Russell King
+ * Copyright (C) 1995-2004 Russell King
  *
  * Delay routines, using a pre-computed "loops_per_second" value.
  */
+#ifndef __ASM_ARM_DELAY_H
+#define __ASM_ARM_DELAY_H
 
 extern void __delay(int loops);
 
+/*
+ * This function intentionally does not exist; if you see references to
+ * it, it means that you're calling udelay() with an out of range value.
+ *
+ * With currently imposed limits, this means that we support a max delay
+ * of 2000us and 671 bogomips
+ */
+extern void __bad_udelay(void);
+
 /*
  * division by multiplication: you don't have to worry about
  * loss of precision.
@@ -19,14 +27,16 @@ extern void __delay(int loops);
  * first constant multiplications gets optimized away if the delay is
  * a constant)
  */
-extern void udelay(unsigned long usecs);
+extern void __udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long);
 
-static inline unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
-{
-       return a * b / c;
-}
+#define MAX_UDELAY_MS 2
 
-       
+#define udelay(n)                                              \
+       (__builtin_constant_p(n) ?                              \
+         ((n) > (MAX_UDELAY_MS * 1000) ? __bad_udelay() :      \
+                       __const_udelay((n) * 0x68dbul)) :       \
+         __udelay(n))
 
 #endif /* defined(_ARM_DELAY_H) */
 
index 3f734c4..a808f3c 100644 (file)
@@ -8,39 +8,16 @@
 
 typedef struct {
        unsigned int __softirq_pending;
-       unsigned int __local_irq_count;
-       unsigned int __local_bh_count;
-       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 depth: 256)
- * - bits 8-15 are the softirq count (max # of softirqs: 256)
- * - bits 16-24 are the hardirq count (max # of hardirqs: 512)
- * - bit 26 is the PREEMPT_ACTIVE flag
- *
- * We optimize HARDIRQ_BITS for immediate constant, and only
- * increase it if really needed.
- */
-#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
@@ -52,7 +29,6 @@ typedef struct {
 
 #define irq_enter()            (preempt_count() += HARDIRQ_OFFSET)
 
-#ifndef CONFIG_SMP
 extern asmlinkage void __do_softirq(void);
 
 #define irq_exit()                                                     \
@@ -62,6 +38,5 @@ extern asmlinkage void __do_softirq(void);
                        __do_softirq();                                 \
                preempt_enable_no_resched();                            \
        } while (0)
-#endif
 
 #endif /* __ASM_HARDIRQ_H */
index 65436fe..97681e3 100644 (file)
@@ -22,7 +22,7 @@
 #define CLCD_UBAS              0x00000010
 #define CLCD_LBAS              0x00000014
 
-#ifndef CONFIG_ARCH_VERSATILE_PB
+#ifndef CONFIG_ARCH_VERSATILE
 #define CLCD_IENB              0x00000018
 #define CLCD_CNTL              0x0000001c
 #else
@@ -141,7 +141,7 @@ struct clcd_fb {
        struct clcd_panel       *panel;
        struct clcd_board       *board;
        void                    *board_data;
-       void                    *regs;
+       void __iomem            *regs;
        u32                     clcd_cntl;
        u32                     cmap[16];
 };
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
index 1855fb7..6051337 100644 (file)
@@ -16,6 +16,7 @@
  *  04-Apr-1999        PJB     Added check_signature.
  *  12-Dec-1999        RMK     More cleanups
  *  18-Jun-2000 RMK    Removed virt_to_* and friends definitions
+ *  05-Oct-2004 BJD     Moved memory string functions to use void __iomem
  */
 #ifndef __ASM_ARM_IO_H
 #define __ASM_ARM_IO_H
  * Generic IO read/write.  These perform native-endian accesses.  Note
  * that some architectures will want to re-define __raw_{read,write}w.
  */
-extern void __raw_writesb(unsigned int addr, const void *data, int bytelen);
-extern void __raw_writesw(unsigned int addr, const void *data, int wordlen);
-extern void __raw_writesl(unsigned int addr, const void *data, int longlen);
+extern void __raw_writesb(void __iomem *addr, const void *data, int bytelen);
+extern void __raw_writesw(void __iomem *addr, const void *data, int wordlen);
+extern void __raw_writesl(void __iomem *addr, const void *data, int longlen);
 
-extern void __raw_readsb(unsigned int addr, void *data, int bytelen);
-extern void __raw_readsw(unsigned int addr, void *data, int wordlen);
-extern void __raw_readsl(unsigned int addr, void *data, int longlen);
+extern void __raw_readsb(void __iomem *addr, void *data, int bytelen);
+extern void __raw_readsw(void __iomem *addr, void *data, int wordlen);
+extern void __raw_readsl(void __iomem *addr, void *data, int longlen);
 
-#define __raw_writeb(v,a)      (*(volatile unsigned char  *)(a) = (v))
-#define __raw_writew(v,a)      (*(volatile unsigned short *)(a) = (v))
-#define __raw_writel(v,a)      (*(volatile unsigned int   *)(a) = (v))
+#define __raw_writeb(v,a)      (*(volatile unsigned char __force  *)(a) = (v))
+#define __raw_writew(v,a)      (*(volatile unsigned short __force *)(a) = (v))
+#define __raw_writel(v,a)      (*(volatile unsigned int __force   *)(a) = (v))
 
-#define __raw_readb(a)         (*(volatile unsigned char  *)(a))
-#define __raw_readw(a)         (*(volatile unsigned short *)(a))
-#define __raw_readl(a)         (*(volatile unsigned int   *)(a))
+#define __raw_readb(a)         (*(volatile unsigned char __force  *)(a))
+#define __raw_readw(a)         (*(volatile unsigned short __force *)(a))
+#define __raw_readl(a)         (*(volatile unsigned int __force   *)(a))
 
 /*
  * Bad read/write accesses...
@@ -131,9 +132,11 @@ extern void __readwrite_bug(const char *fn);
 /*
  * String version of IO memory access ops:
  */
-extern void _memcpy_fromio(void *, unsigned long, size_t);
-extern void _memcpy_toio(unsigned long, const void *, size_t);
-extern void _memset_io(unsigned long, int, size_t);
+extern void _memcpy_fromio(void *, void __iomem *, size_t);
+extern void _memcpy_toio(void __iomem *, const void *, size_t);
+extern void _memset_io(void __iomem *, int, size_t);
+
+#define mmiowb()
 
 /*
  *  Memory access primitives
@@ -153,17 +156,17 @@ extern void _memset_io(unsigned long, int, size_t);
 #define readw_relaxed(addr) readw(addr)
 #define readl_relaxed(addr) readl(addr)
 
-#define readsb(p,d,l)          __raw_readsb((unsigned int)__mem_pci(p),d,l)
-#define readsw(p,d,l)          __raw_readsw((unsigned int)__mem_pci(p),d,l)
-#define readsl(p,d,l)          __raw_readsl((unsigned int)__mem_pci(p),d,l)
+#define readsb(p,d,l)          __raw_readsb(__mem_pci(p),d,l)
+#define readsw(p,d,l)          __raw_readsw(__mem_pci(p),d,l)
+#define readsl(p,d,l)          __raw_readsl(__mem_pci(p),d,l)
 
 #define writeb(v,c)            __raw_writeb(v,__mem_pci(c))
 #define writew(v,c)            __raw_writew(cpu_to_le16(v),__mem_pci(c))
 #define writel(v,c)            __raw_writel(cpu_to_le32(v),__mem_pci(c))
 
-#define writesb(p,d,l)         __raw_writesb((unsigned int)__mem_pci(p),d,l)
-#define writesw(p,d,l)         __raw_writesw((unsigned int)__mem_pci(p),d,l)
-#define writesl(p,d,l)         __raw_writesl((unsigned int)__mem_pci(p),d,l)
+#define writesb(p,d,l)         __raw_writesb(__mem_pci(p),d,l)
+#define writesw(p,d,l)         __raw_writesw(__mem_pci(p),d,l)
+#define writesl(p,d,l)         __raw_writesl(__mem_pci(p),d,l)
 
 #define memset_io(c,v,l)       _memset_io(__mem_pci(c),(v),(l))
 #define memcpy_fromio(a,c,l)   _memcpy_fromio((a),__mem_pci(c),(l))
@@ -173,7 +176,7 @@ extern void _memset_io(unsigned long, int, size_t);
                                eth_copy_and_sum((s),__mem_pci(c),(l),(b))
 
 static inline int
-check_signature(unsigned long io_addr, const unsigned char *signature,
+check_signature(void __iomem *io_addr, const unsigned char *signature,
                int length)
 {
        int retval = 0;
@@ -223,23 +226,6 @@ out:
 #define isa_eth_io_copy_and_sum(a,b,c,d) \
                                eth_copy_and_sum((a),__mem_isa(b),(c),(d))
 
-static inline int
-isa_check_signature(unsigned long io_addr, const unsigned char *signature,
-                   int length)
-{
-       int retval = 0;
-       do {
-               if (isa_readb(io_addr) != *signature)
-                       goto out;
-               io_addr++;
-               signature++;
-               length--;
-       } while (length);
-       retval = 1;
-out:
-       return retval;
-}
-
 #else  /* __mem_isa */
 
 #define isa_readb(addr)                        (__readwrite_bug("isa_readb"),0)
@@ -255,8 +241,6 @@ out:
 #define isa_eth_io_copy_and_sum(a,b,c,d) \
                                __readwrite_bug("isa_eth_io_copy_and_sum")
 
-#define isa_check_signature(io,sig,len)        (0)
-
 #endif /* __mem_isa */
 
 /*
@@ -265,8 +249,8 @@ out:
  * ioremap takes a PCI memory address, as specified in
  * Documentation/IO-mapping.txt.
  */
-extern void * __ioremap(unsigned long, size_t, unsigned long, unsigned long);
-extern void __iounmap(void *addr);
+extern void __iomem * __ioremap(unsigned long, size_t, unsigned long, unsigned long);
+extern void __iounmap(void __iomem *addr);
 
 #ifndef __arch_ioremap
 #define ioremap(cookie,size)           __ioremap(cookie,size,0,1)
index 286be7c..f97912f 100644 (file)
@@ -21,8 +21,7 @@
 
 struct irqaction;
 
-#define disable_irq_nosync(i) disable_irq(i)
-
+extern void disable_irq_nosync(unsigned int);
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
index f7b86a1..a92887d 100644 (file)
@@ -2,18 +2,33 @@
  *  linux/include/asm-arm/mach/flash.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 ASMARM_MACH_FLASH_H
-#define ASMAMR_MACH_FLASH_H
+#define ASMARM_MACH_FLASH_H
 
 struct mtd_partition;
 
+/*
+ * map_name:   the map probe function name
+ * width:      width of mapped device
+ * init:       method called at driver/device initialisation
+ * exit:       method called at driver/device removal
+ * set_vpp:    method called to enable or disable VPP
+ * parts:      optional array of mtd_partitions for static partitioning
+ * nr_parts:   number of mtd_partitions for static partitoning
+ */
 struct flash_platform_data {
        const char      *map_name;
-       int             width;
+       unsigned int    width;
        int             (*init)(void);
        void            (*exit)(void);
        void            (*set_vpp)(int on);
+       struct mtd_partition *parts;
+       unsigned int    nr_parts;
 };
 
 #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
index bea9af3..c6ae545 100644 (file)
@@ -97,23 +97,6 @@ void __set_irq_handler(unsigned int irq, irq_handler_t, int);
 void set_irq_chip(unsigned int irq, struct irqchip *);
 void set_irq_flags(unsigned int irq, unsigned int flags);
 
-#ifdef not_yet
-/*
- * This is to be used by the top-level machine IRQ decoder only.
- */
-static inline void call_irq(struct pt_regs *regs, unsigned int irq)
-{
-       struct irqdesc *desc = irq_desc + irq;
-
-       spin_lock(&irq_controller_lock);
-       desc->handle(irq, desc, regs);
-       spin_unlock(&irq_controller_lock);
-
-       if (softirq_pending(smp_processor_id()))
-               do_softirq();
-}
-#endif
-
 #define IRQF_VALID     (1 << 0)
 #define IRQF_PROBE     (1 << 1)
 #define IRQF_NOAUTOEN  (1 << 2)
index 284df8b..0dbac30 100644 (file)
@@ -21,8 +21,10 @@ struct meminfo;
 #define MT_DEVICE      0
 #define MT_CACHECLEAN  1
 #define MT_MINICLEAN   2
-#define MT_VECTORS     3
-#define MT_MEMORY      4
+#define MT_LOW_VECTORS 3
+#define MT_HIGH_VECTORS        4
+#define MT_MEMORY      5
+#define MT_ROM         6
 
 extern void create_memmap_holes(struct meminfo *);
 extern void memtable_init(struct meminfo *);
index 41a946e..1b3555d 100644 (file)
@@ -7,7 +7,6 @@
 #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 *);
index 51728ed..5cf4fd6 100644 (file)
 #ifndef __ASM_ARM_MACH_TIME_H
 #define __ASM_ARM_MACH_TIME_H
 
-extern void (*init_arch_time)(void);
+#include <linux/sysdev.h>
 
-extern int (*set_rtc)(void);
-extern unsigned long (*gettimeoffset)(void);
+/*
+ * This is our kernel timer structure.
+ *
+ * - init
+ *   Initialise the kernels jiffy timer source, claim interrupt
+ *   using setup_irq.  This is called early on during initialisation
+ *   while interrupts are still disabled on the local CPU.
+ * - suspend
+ *   Suspend the kernel jiffy timer source, if necessary.  This
+ *   is called with interrupts disabled, after all normal devices
+ *   have been suspended.  If no action is required, set this to
+ *   NULL.
+ * - resume
+ *   Resume the kernel jiffy timer source, if necessary.  This
+ *   is called with interrupts disabled before any normal devices
+ *   are resumed.  If no action is required, set this to NULL.
+ * - offset
+ *   Return the timer offset in microseconds since the last timer
+ *   interrupt.  Note: this must take account of any unprocessed
+ *   timer interrupt which may be pending.
+ */
+struct sys_timer {
+       struct sys_device       dev;
+       void                    (*init)(void);
+       void                    (*suspend)(void);
+       void                    (*resume)(void);
+       unsigned long           (*offset)(void);
+};
 
+extern struct sys_timer *system_timer;
 extern void timer_tick(struct pt_regs *);
 
+/*
+ * Kernel time keeping support.
+ */
+extern int (*set_rtc)(void);
 extern void save_time_delta(struct timespec *delta, struct timespec *rtc);
 extern void restore_time_delta(struct timespec *delta, struct timespec *rtc);
 
index a4cb792..4af9c41 100644 (file)
@@ -80,18 +80,17 @@ static inline void
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
          struct task_struct *tsk)
 {
+       unsigned int cpu = smp_processor_id();
+
        if (prev != next) {
+               cpu_set(cpu, next->cpu_vm_mask);
                check_context(next);
                cpu_switch_mm(next->pgd, next);
+               cpu_clear(cpu, prev->cpu_vm_mask);
        }
 }
 
 #define deactivate_mm(tsk,mm)  do { } while (0)
-
-static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
-{
-       check_context(next);
-       cpu_switch_mm(next->pgd, next);
-}
+#define activate_mm(prev,next) switch_mm(prev, next, NULL)
 
 #endif
index cdf4b69..e142a2a 100644 (file)
@@ -62,19 +62,19 @@ typedef struct {
 
 #undef __FD_SET
 #define __FD_SET(fd, fdsetp) \
-               (((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31)))
+               (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] |= (1<<((fd) & 31)))
 
 #undef __FD_CLR
 #define __FD_CLR(fd, fdsetp) \
-               (((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1<<(fd & 31)))
+               (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] &= ~(1<<((fd) & 31)))
 
 #undef __FD_ISSET
 #define __FD_ISSET(fd, fdsetp) \
-               ((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1<<(fd & 31))) != 0)
+               ((((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] & (1<<((fd) & 31))) != 0)
 
 #undef __FD_ZERO
 #define __FD_ZERO(fdsetp) \
-               (memset (fdsetp, 0, sizeof (*(fd_set *)fdsetp)))
+               (memset (fdsetp, 0, sizeof (*(fd_set *)(fdsetp))))
 
 #endif
 
index a3116e9..a9c75b2 100644 (file)
@@ -24,13 +24,13 @@ struct processor;
  *
  * NOTE! The following structure is defined by assembly
  * language, NOT C code.  For more information, check:
- *  arch/arm/mm/proc-*.S and arch/arm/kernel/head-armv.S
+ *  arch/arm/mm/proc-*.S and arch/arm/kernel/head.S
  */
 struct proc_info_list {
        unsigned int            cpu_val;
        unsigned int            cpu_mask;
-       unsigned long           __cpu_mmu_flags;        /* used by head-armv.S */
-       unsigned long           __cpu_flush;            /* used by head-armv.S */
+       unsigned long           __cpu_mmu_flags;        /* used by head.S */
+       unsigned long           __cpu_flush;            /* used by head.S */
        const char              *arch_name;
        const char              *elf_name;
        unsigned int            elf_hwcap;
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
index 1cce84a..015b262 100644 (file)
 #ifndef __ASM_SERIAL_H
 #define __ASM_SERIAL_H
 
-#include <asm/arch/serial.h>
-
-#define SERIAL_PORT_DFNS               \
-       STD_SERIAL_PORT_DEFNS           \
-       EXTRA_SERIAL_PORT_DEFNS
+#define BASE_BAUD      (1843200 / 16)
 
 #endif
index 1a908d3..8a864b1 100644 (file)
@@ -262,7 +262,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
        if (tlb_flag(TLB_WB))
                asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
 
-       if (mm == current->active_mm) {
+       if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask)) {
                if (tlb_flag(TLB_V3_FULL))
                        asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero));
                if (tlb_flag(TLB_V4_U_FULL))
@@ -292,7 +292,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
        if (tlb_flag(TLB_WB))
                asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
 
-       if (vma->vm_mm == current->active_mm) {
+       if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
                if (tlb_flag(TLB_V3_PAGE))
                        asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (uaddr));
                if (tlb_flag(TLB_V4_U_PAGE))
index 52feb95..bb5a5fa 100644 (file)
@@ -15,23 +15,8 @@ typedef struct {
 
 #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 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
- */
-#define PREEMPT_BITS   8
-#define SOFTIRQ_BITS   8
 #define HARDIRQ_BITS   8
 
-#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
index b1f1812..bc20793 100644 (file)
@@ -320,6 +320,8 @@ DECLARE_IO(int,l,"")
 #define writesw(p,d,l)                        __readwrite_bug("writesw")
 #define writesl(p,d,l)                        __readwrite_bug("writesl")
 
+#define mmiowb()
+
 /* the following macro is depreciated */
 #define ioaddr(port)                    __ioaddr((port))
 
index 4e28c83..502aed5 100644 (file)
@@ -17,29 +17,8 @@ typedef struct {
 
 #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
 #define HARDIRQ_BITS   8
 
-#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
index e3185b1..fd9de95 100644 (file)
@@ -9,7 +9,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
                   int flag)
 {
        BUG();
-       return 0;
+       return NULL;
 }
 
 static inline void
index d20dc0f..4dd2384 100644 (file)
 
 #define        ENOMEDIUM       123     /* No medium found */
 #define        EMEDIUMTYPE     124     /* Wrong medium type */
+#define        ECANCELED       125     /* Operation Canceled */
+#define        ENOKEY          126     /* Required key not available */
+#define        EKEYEXPIRED     127     /* Key has expired */
+#define        EKEYREVOKED     128     /* Key has been revoked */
+#define        EKEYREJECTED    129     /* Key was rejected by service */
 
 #endif
index 40cca57..9d4cc47 100644 (file)
@@ -24,4 +24,11 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 
 #define pcibios_scan_all_fns(a, b)     0
 
+#ifndef HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+       return channel ? 15 : 14;
+}
+#endif /* HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ */
+
 #endif
index 8f84159..ec96e8b 100644 (file)
@@ -45,9 +45,4 @@
 #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_GENERIC_TOPOLOGY_H */
index 7183e7e..cbccbbd 100644 (file)
 
 extern __inline__ void __delay(unsigned long loops)
 {
-       __asm__ __volatile__ ("mov.l %0,er0\n\t"
-                             "1:\n\t"
-                             "dec.l #1,er0\n\t"
+       __asm__ __volatile__ ("1:\n\t"
+                             "dec.l #1,%0\n\t"
                              "bne 1b"
-                             ::"r" (loops):"er0");
+                             :"=r" (loops):"0"(loops));
 }
 
 /*
index 6612725..3a08544 100644 (file)
@@ -96,6 +96,8 @@ typedef unsigned long sigset_t;
 #define SA_ONESHOT     SA_RESETHAND
 #define SA_INTERRUPT   0x20000000 /* dummy -- ignored */
 
+#define SA_RESTORER    0x04000000
+
 /* 
  * sigaltstack controls
  */
index 2a29101..b91dae2 100644 (file)
@@ -2,7 +2,6 @@
 #define _H8300_SYSTEM_H
 
 #include <linux/config.h> /* get configuration macros */
-#include <linux/kernel.h>
 #include <linux/linkage.h>
 
 #define prepare_to_switch()    do { } while(0)
@@ -119,7 +118,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
     __asm__ __volatile__
     ("mov.b %2,%0\n\t"
      "mov.b %1,%2"
-    : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "er0","memory");
+    : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory");
     break;
   case 2:
     __asm__ __volatile__
index 7987d6c..0bcf8f8 100644 (file)
@@ -1,22 +1,11 @@
 #ifndef _H8300_UCONTEXT_H
 #define _H8300_UCONTEXT_H
 
-typedef int greg_t;
-#define NGREG 10
-typedef greg_t gregset_t[NGREG];
-
-struct mcontext {
-       int version;
-       gregset_t gregs;
-};
-
-#define MCONTEXT_VERSION 1
-
 struct ucontext {
        unsigned long     uc_flags;
        struct ucontext  *uc_link;
        stack_t           uc_stack;
-       struct mcontext   uc_mcontext;
+       struct sigcontext uc_mcontext;
        sigset_t          uc_sigmask;   /* mask last for extensibility */
 };
 
index 8f5a075..95db6fd 100644 (file)
@@ -14,48 +14,6 @@ typedef struct {
 
 #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
-#define HARDIRQ_BITS   8
-
-#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 nmi_enter()            (irq_enter())
-#define nmi_exit()             (preempt_count() -= HARDIRQ_OFFSET)
-
-#define irq_enter()            (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)
+void ack_bad_irq(unsigned int irq);
 
 #endif /* __ASM_HARDIRQ_H */
index 083e3b8..479e976 100644 (file)
@@ -178,11 +178,13 @@ static inline void writel(unsigned int b, volatile void __iomem *addr)
 #define __raw_writew writew
 #define __raw_writel writel
 
+#define mmiowb()
+
 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)
+static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
 {
        __memcpy(dst, (void __force *) src, count);
 }
@@ -246,36 +248,6 @@ out:
        return retval;
 }
 
-/**
- *     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;
-       do {
-               if (isa_readb(io_addr) != *signature)
-                       goto out;
-               io_addr++;
-               signature++;
-               length--;
-       } while (length);
-       retval = 1;
-out:
-       return retval;
-}
-
 /*
  *     Cache management
  *
index 566e34a..c0e8ad3 100644 (file)
@@ -38,6 +38,13 @@ typedef u8 kprobe_opcode_t;
        ? (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[MAX_INSN_SIZE];
+};
+
+
 /* trap3/1 are intr gates for kprobes.  So, restore the status of IF,
  * if necessary, before executing the original int3/1 (trap) handler.
  */
index 9eb6c9d..03dd13a 100644 (file)
@@ -16,6 +16,9 @@
 static inline void do_timer_interrupt_hook(struct pt_regs *regs)
 {
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
 /*
  * In the SMP case we use the local APIC timer interrupt to do the
  * profiling, except when we simulate SMP mode on a uniprocessor
index 1cce2b9..2b9e6d5 100644 (file)
@@ -22,6 +22,7 @@ static inline void mpc_oem_pci_bus(struct mpc_config_bus *m,
 {
 }
 
+extern int usb_early_handoff;
 static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, 
                char *productid)
 {
@@ -31,6 +32,7 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
                         || !strncmp(productid, "RUTHLESS SMP", 12))){
                use_cyclone = 1; /*enable cyclone-timer*/
                setup_summit();
+               usb_early_handoff = 1;
                return 1;
        }
        return 0;
@@ -44,6 +46,7 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
             || !strncmp(oem_table_id, "EXA", 3))){
                use_cyclone = 1; /*enable cyclone-timer*/
                setup_summit();
+               usb_early_handoff = 1;
                return 1;
        }
        return 0;
index 1728732..33acd50 100644 (file)
@@ -9,6 +9,9 @@ static inline void do_timer_interrupt_hook(struct pt_regs *regs)
        co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR);
 
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
 /*
  * In the SMP case we use the local APIC timer interrupt to do the
  * profiling, except when we simulate SMP mode on a uniprocessor
index 75c642f..ae510e5 100644 (file)
@@ -4,6 +4,9 @@
 static inline void do_timer_interrupt_hook(struct pt_regs *regs)
 {
        do_timer(regs);
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(regs));
+#endif
 
        voyager_timer_interrupt(regs);
 }
index c1aeb27..e13c6ff 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/mmzone.h>
 #include <linux/node.h>
 #include <linux/topology.h>
+#include <linux/nodemask.h>
 
 struct i386_node {
        struct node node;
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"
index 1db03a6..1452af1 100644 (file)
@@ -87,15 +87,15 @@ 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 */);
+fastcall void __down_failed(void /* special register calling convention */);
+fastcall int  __down_failed_interruptible(void  /* params in registers */);
+fastcall int  __down_failed_trylock(void  /* params in registers */);
+fastcall 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);
+fastcall void __down(struct semaphore * sem);
+fastcall int  __down_interruptible(struct semaphore * sem);
+fastcall int  __down_trylock(struct semaphore * sem);
+fastcall void __up(struct semaphore * sem);
 
 /*
  * This is ugly, but we want the default case to fall through.
@@ -111,12 +111,13 @@ static inline void down(struct semaphore * sem)
                "js 2f\n"
                "1:\n"
                LOCK_SECTION_START("")
-               "2:\tcall __down_failed\n\t"
+               "2:\tlea %0,%%eax\n\t"
+               "call __down_failed\n\t"
                "jmp 1b\n"
                LOCK_SECTION_END
                :"=m" (sem->count)
-               :"c" (sem)
-               :"memory");
+               :
+               :"memory","ax");
 }
 
 /*
@@ -135,11 +136,12 @@ static inline int down_interruptible(struct semaphore * sem)
                "xorl %0,%0\n"
                "1:\n"
                LOCK_SECTION_START("")
-               "2:\tcall __down_failed_interruptible\n\t"
+               "2:\tlea %1,%%eax\n\t"
+               "call __down_failed_interruptible\n\t"
                "jmp 1b\n"
                LOCK_SECTION_END
                :"=a" (result), "=m" (sem->count)
-               :"c" (sem)
+               :
                :"memory");
        return result;
 }
@@ -159,11 +161,12 @@ static inline int down_trylock(struct semaphore * sem)
                "xorl %0,%0\n"
                "1:\n"
                LOCK_SECTION_START("")
-               "2:\tcall __down_failed_trylock\n\t"
+               "2:\tlea %1,%%eax\n\t"
+               "call __down_failed_trylock\n\t"
                "jmp 1b\n"
                LOCK_SECTION_END
                :"=a" (result), "=m" (sem->count)
-               :"c" (sem)
+               :
                :"memory");
        return result;
 }
@@ -182,13 +185,14 @@ static inline void up(struct semaphore * sem)
                "jle 2f\n"
                "1:\n"
                LOCK_SECTION_START("")
-               "2:\tcall __up_wakeup\n\t"
+               "2:\tlea %0,%%eax\n\t"
+               "call __up_wakeup\n\t"
                "jmp 1b\n"
                LOCK_SECTION_END
                ".subsection 0\n"
                :"=m" (sem->count)
-               :"c" (sem)
-               :"memory");
+               :
+               :"memory","ax");
 }
 
 #endif
index cb8ab74..d2c8360 100644 (file)
@@ -69,8 +69,25 @@ static inline cpumask_t pcibus_to_cpumask(int bus)
 /* Node-to-Node distance */
 #define node_distance(from, to) ((from) != (to))
 
-/* Cross-node load balancing interval. */
-#define NODE_BALANCE_RATE 100
+/* sched_domains SD_NODE_INIT for NUMAQ machines */
+#define SD_NODE_INIT (struct sched_domain) {           \
+       .span                   = CPU_MASK_NONE,        \
+       .parent                 = NULL,                 \
+       .groups                 = NULL,                 \
+       .min_interval           = 8,                    \
+       .max_interval           = 32,                   \
+       .busy_factor            = 32,                   \
+       .imbalance_pct          = 125,                  \
+       .cache_hot_time         = (10*1000),            \
+       .cache_nice_tries       = 1,                    \
+       .per_cpu_gain           = 100,                  \
+       .flags                  = SD_LOAD_BALANCE       \
+                               | SD_BALANCE_EXEC       \
+                               | SD_WAKE_BALANCE,      \
+       .last_balance           = jiffies,              \
+       .balance_interval       = 1,                    \
+       .nr_balance_failed      = 0,                    \
+}
 
 #else /* !CONFIG_NUMA */
 /*
index 491996a..b097596 100644 (file)
 #define __ARCH_IRQ_STAT        1
 
 #define softirq_pending(cpu)           (cpu_data(cpu)->softirq_pending)
-#define syscall_count(cpu)             /* unused on IA-64 */
-#define ksoftirqd_task(cpu)            (cpu_data(cpu)->ksoftirqd)
-#define nmi_count(cpu)                 0
-
 #define local_softirq_pending()                (local_cpu_data->softirq_pending)
-#define local_syscall_count()          /* unused on IA-64 */
-#define local_ksoftirqd_task()         (local_cpu_data->ksoftirqd)
-#define local_nmi_count()              0
 
-/*
- * 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-29 are the hardirq count (max # of hardirqs: 16384)
- *
- * - (bit 63 is the PREEMPT_ACTIVE flag---not currently implemented.)
- *
- * PREEMPT_MASK: 0x000000ff
- * SOFTIRQ_MASK: 0x0000ff00
- * HARDIRQ_MASK: 0x3fff0000
- */
-
-#define PREEMPT_BITS   8
-#define SOFTIRQ_BITS   8
 #define HARDIRQ_BITS   14
 
-#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:
index 4d19a5b..263cacb 100644 (file)
@@ -32,7 +32,8 @@
  */
 #define IO_SPACE_LIMIT         0xffffffffffffffffUL
 
-#define MAX_IO_SPACES                  16
+#define MAX_IO_SPACES_BITS             4
+#define MAX_IO_SPACES                  (1UL << MAX_IO_SPACES_BITS)
 #define IO_SPACE_BITS                  24
 #define IO_SPACE_SIZE                  (1UL << IO_SPACE_BITS)
 
@@ -52,10 +53,24 @@ extern unsigned int num_io_spaces;
 
 # ifdef __KERNEL__
 
+/*
+ * All MMIO iomem cookies are in region 6; anything less is a PIO cookie:
+ *     0xCxxxxxxxxxxxxxxx      MMIO cookie (return from ioremap)
+ *     0x000000001SPPPPPP      PIO cookie (S=space number, P..P=port)
+ *
+ * ioread/writeX() uses the leading 1 in PIO cookies (PIO_OFFSET) to catch
+ * code that uses bare port numbers without the prerequisite pci_iomap().
+ */
+#define PIO_OFFSET             (1UL << (MAX_IO_SPACES_BITS + IO_SPACE_BITS))
+#define PIO_MASK               (PIO_OFFSET - 1)
+#define PIO_RESERVED           __IA64_UNCACHED_OFFSET
+#define HAVE_ARCH_PIO_SIZE
+
 #include <asm/intrinsics.h>
 #include <asm/machvec.h>
 #include <asm/page.h>
 #include <asm/system.h>
+#include <asm-generic/iomap.h>
 
 /*
  * Change virtual addresses to physical addresses and vv.
@@ -91,6 +106,20 @@ extern int valid_phys_addr_range (unsigned long addr, size_t *count); /* efi.c *
  */
 #define __ia64_mf_a()  ia64_mfa()
 
+/**
+ * ___ia64_mmiowb - I/O write barrier
+ *
+ * Ensure ordering of I/O space writes.  This will make sure that writes
+ * following the barrier will arrive after all previous writes.  For most
+ * ia64 platforms, this is a simple 'mf.a' instruction.
+ *
+ * See Documentation/DocBook/deviceiobook.tmpl for more information.
+ */
+static inline void ___ia64_mmiowb(void)
+{
+       ia64_mfa();
+}
+
 static inline const unsigned long
 __ia64_get_io_port_base (void)
 {
@@ -133,6 +162,7 @@ __ia64_mk_io_addr (unsigned long port)
 #define __ia64_writew  ___ia64_writew
 #define __ia64_writel  ___ia64_writel
 #define __ia64_writeq  ___ia64_writeq
+#define __ia64_mmiowb  ___ia64_mmiowb
 
 /*
  * For the in/out routines, we need to do "mf.a" _after_ doing the I/O access to ensure
@@ -267,6 +297,7 @@ __outsl (unsigned long port, const void *src, unsigned long count)
 #define __outb         platform_outb
 #define __outw         platform_outw
 #define __outl         platform_outl
+#define __mmiowb       platform_mmiowb
 
 #define inb(p)         __inb(p)
 #define inw(p)         __inw(p)
@@ -280,6 +311,7 @@ __outsl (unsigned long port, const void *src, unsigned long count)
 #define outsb(p,s,c)   __outsb(p,s,c)
 #define outsw(p,s,c)   __outsw(p,s,c)
 #define outsl(p,s,c)   __outsl(p,s,c)
+#define mmiowb()       __mmiowb()
 
 /*
  * The address passed to these functions are ioremap()ped already.
index 115a76a..0d7386a 100644 (file)
@@ -12,6 +12,7 @@ extern ia64_mv_inl_t __ia64_inl;
 extern ia64_mv_outb_t __ia64_outb;
 extern ia64_mv_outw_t __ia64_outw;
 extern ia64_mv_outl_t __ia64_outl;
+extern ia64_mv_mmiowb_t __ia64_mmiowb;
 extern ia64_mv_readb_t __ia64_readb;
 extern ia64_mv_readw_t __ia64_readw;
 extern ia64_mv_readl_t __ia64_readl;
index 2af819b..0bef195 100644 (file)
@@ -2,7 +2,7 @@
 #define _ASM_IA64_PTRACE_H
 
 /*
- * Copyright (C) 1998-2003 Hewlett-Packard Co
+ * Copyright (C) 1998-2004 Hewlett-Packard Co
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  *     Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 2003 Intel Co
@@ -110,7 +110,11 @@ struct pt_regs {
 
        unsigned long cr_ipsr;          /* interrupted task's psr */
        unsigned long cr_iip;           /* interrupted task's instruction pointer */
-       unsigned long cr_ifs;           /* interrupted task's function state */
+       /*
+        * interrupted task's function state; if bit 63 is cleared, it
+        * contains syscall's ar.pfs.pfm:
+        */
+       unsigned long cr_ifs;
 
        unsigned long ar_unat;          /* interrupted task's NaT register (preserved) */
        unsigned long ar_pfs;           /* prev function state  */
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 */
index d4105bd..5b0dd8c 100644 (file)
  */
 #define node_to_first_cpu(node) (__ffs(node_to_cpumask(node)))
 
-/* Cross-node load balancing interval. */
-#define NODE_BALANCE_RATE 10
-
 void build_cpu_to_node_map(void);
 
+/* sched_domains SD_NODE_INIT for IA64 NUMA machines */
+#define SD_NODE_INIT (struct sched_domain) {           \
+       .span                   = CPU_MASK_NONE,        \
+       .parent                 = NULL,                 \
+       .groups                 = NULL,                 \
+       .min_interval           = 80,                   \
+       .max_interval           = 320,                  \
+       .busy_factor            = 320,                  \
+       .imbalance_pct          = 125,                  \
+       .cache_hot_time         = (10*1000000),         \
+       .cache_nice_tries       = 1,                    \
+       .per_cpu_gain           = 100,                  \
+       .flags                  = SD_LOAD_BALANCE       \
+                               | SD_BALANCE_EXEC       \
+                               | SD_WAKE_BALANCE,      \
+       .last_balance           = jiffies,              \
+       .balance_interval       = 1,                    \
+       .nr_balance_failed      = 0,                    \
+}
+
+/* sched_domains SD_ALLNODES_INIT for IA64 NUMA machines */
+#define SD_ALLNODES_INIT (struct sched_domain) {       \
+       .span                   = CPU_MASK_NONE,        \
+       .parent                 = NULL,                 \
+       .groups                 = NULL,                 \
+       .min_interval           = 80,                   \
+       .max_interval           = 320,                  \
+       .busy_factor            = 320,                  \
+       .imbalance_pct          = 125,                  \
+       .cache_hot_time         = (10*1000000),         \
+       .cache_nice_tries       = 1,                    \
+       .per_cpu_gain           = 100,                  \
+       .flags                  = SD_LOAD_BALANCE       \
+                               | SD_BALANCE_EXEC,      \
+       .last_balance           = jiffies,              \
+       .balance_interval       = 100*(63+num_online_cpus())/64,   \
+       .nr_balance_failed      = 0,                    \
+}
+
 #endif /* CONFIG_NUMA */
 
 #include <asm-generic/topology.h>
index f601fcb..af94c14 100644 (file)
 #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
@@ -92,7 +54,6 @@
 #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
 
@@ -154,7 +115,7 @@ typedef elf_fpreg_t elf_fpregset_t;
    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));
+       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.  */
index b46a265..78cb4c9 100644 (file)
@@ -13,34 +13,12 @@ typedef struct {
 
 #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
index 8389f24..be64f24 100644 (file)
@@ -35,7 +35,7 @@
 static __inline__ int ide_default_irq(unsigned long base)
 {
        switch (base) {
-#if defined(CONFIG_PLAT_M32700UT)
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2)
                case 0x1f0: return PLD_IRQ_CFIREQ;
                default:
                        return 0;
index 97a64d3..a5d3abe 100644 (file)
@@ -151,6 +151,9 @@ static inline void _writel(unsigned long l, unsigned long addr)
 #define __raw_readb readb
 #define __raw_readw readw
 #define __raw_readl readl
+#define readb_relaxed readb
+#define readw_relaxed readw
+#define readl_relaxed readl
 
 #define writeb(val, addr)  _writeb((val), (unsigned long)(addr))
 #define writew(val, addr)  _writew((val), (unsigned long)(addr))
@@ -159,10 +162,12 @@ static inline void _writel(unsigned long l, unsigned long addr)
 #define __raw_writew writew
 #define __raw_writel writel
 
+#define mmiowb()
+
 #define flush_write_buffers() do { } while (0)  /* M32R_FIXME */
 
 /**
- *     isa_check_signature             -       find BIOS signatures
+ *     check_signature         -       find BIOS signatures
  *     @io_addr: mmio address to check
  *     @signature:  signature block
  *     @length: length of signature
@@ -174,14 +179,14 @@ static inline void _writel(unsigned long l, unsigned long addr)
  *     check_signature.
  */
 
-static inline int isa_check_signature(unsigned long io_addr,
+static inline int check_signature(void __iomem *io_addr,
         const unsigned char *signature, int length)
 {
         int retval = 0;
 #if 0
-printk("isa_check_signature\n");
+printk("check_signature\n");
         do {
-                if (isa_readb(io_addr) != *signature)
+                if (readb(io_addr) != *signature)
                         goto out;
                 io_addr++;
                 signature++;
index 38e3a73..b560340 100644 (file)
 #define M32R_CPM_CLKMOD_PORTL    (0x04+M32R_CPM_OFFSET)
 #define M32R_CPM_PLLCR_PORTL     (0x08+M32R_CPM_OFFSET)
 
+/*
+ * DMA Controller registers.
+ */
+#define M32R_DMA_OFFSET                (0x000F8000+M32R_SFR_OFFSET)
+
+#define M32R_DMAEN_PORTL       (0x000+M32R_DMA_OFFSET)
+#define M32R_DMAISTS_PORTL     (0x004+M32R_DMA_OFFSET)
+#define M32R_DMAEDET_PORTL     (0x008+M32R_DMA_OFFSET)
+#define M32R_DMAASTS_PORTL     (0x00c+M32R_DMA_OFFSET)
+
+#define M32R_DMA0CR0_PORTL     (0x100+M32R_DMA_OFFSET)
+#define M32R_DMA0CR1_PORTL     (0x104+M32R_DMA_OFFSET)
+#define M32R_DMA0CSA_PORTL     (0x108+M32R_DMA_OFFSET)
+#define M32R_DMA0RSA_PORTL     (0x10c+M32R_DMA_OFFSET)
+#define M32R_DMA0CDA_PORTL     (0x110+M32R_DMA_OFFSET)
+#define M32R_DMA0RDA_PORTL     (0x114+M32R_DMA_OFFSET)
+#define M32R_DMA0CBCUT_PORTL   (0x118+M32R_DMA_OFFSET)
+#define M32R_DMA0RBCUT_PORTL   (0x11c+M32R_DMA_OFFSET)
+
+#define M32R_DMA1CR0_PORTL     (0x200+M32R_DMA_OFFSET)
+#define M32R_DMA1CR1_PORTL     (0x204+M32R_DMA_OFFSET)
+#define M32R_DMA1CSA_PORTL     (0x208+M32R_DMA_OFFSET)
+#define M32R_DMA1RSA_PORTL     (0x20c+M32R_DMA_OFFSET)
+#define M32R_DMA1CDA_PORTL     (0x210+M32R_DMA_OFFSET)
+#define M32R_DMA1RDA_PORTL     (0x214+M32R_DMA_OFFSET)
+#define M32R_DMA1CBCUT_PORTL   (0x218+M32R_DMA_OFFSET)
+#define M32R_DMA1RBCUT_PORTL   (0x21c+M32R_DMA_OFFSET)
+
 /*
  * Multi Function Timer 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)
+#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_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 */
+#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_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)
index 8894d84..30bef95 100644 (file)
@@ -408,7 +408,8 @@ static __inline__ void pmd_set(pmd_t * pmdp, pte_t * ptep)
 /* 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 io_remap_page_range(vma, vaddr, paddr, size, prot)             \
+               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
index 24caabe..b2bdd45 100644 (file)
@@ -1,28 +1,23 @@
 #ifndef _ASM_M32R_PROCESSOR_H
 #define _ASM_M32R_PROCESSOR_H
 
-/* $Id$ */
-
 /*
+ * include/asm-m32r/processor.h
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2001  by Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ * Copyright (C) 1994  Linus Torvalds
+ * Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ * Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
  */
 
-/*
- * 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").
@@ -53,7 +48,7 @@ extern struct cpuinfo_m32r boot_cpu_data;
 extern struct cpuinfo_m32r cpu_data[];
 #define current_cpu_data cpu_data[smp_processor_id()]
 #else
-#define cpu_data &boot_cpu_data
+#define cpu_data (&boot_cpu_data)
 #define current_cpu_data boot_cpu_data
 #endif
 
@@ -141,17 +136,6 @@ unsigned long get_wchan(struct task_struct *p);
 
 #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()
+#define cpu_relax()    barrier()
 
 #endif /* _ASM_M32R_PROCESSOR_H */
index 3696bb1..ec3cdf6 100644 (file)
@@ -29,7 +29,7 @@
 #  define RTC_TCR_4KOHM        0x02    /* xxxxxx10 4kOhm */
 #  define RTC_TCR_8KOHM        0x03    /* xxxxxx11 8kOhm */
 
-#ifdef CONFIG_M32700UT_DS1302
+#ifdef CONFIG_DS1302
 extern unsigned char ds1302_readreg(int reg);
 extern void ds1302_writereg(int reg, unsigned char val);
 extern int ds1302_init(void);
index aa5a829..5ace370 100644 (file)
@@ -136,6 +136,7 @@ struct termios {
 #define  B3500000 0010016
 #define  B4000000 0010017
 #define CIBAUD   002003600000  /* input baud rate (not used) */
+#define CTVB     004000000000          /* VisioBraille Terminal flow control */
 #define CMSPAR   010000000000          /* mark or space (stick) parity */
 #define CRTSCTS          020000000000          /* flow control */
 
index b5a3ea1..299a89d 100644 (file)
@@ -45,9 +45,4 @@
 #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 */
index a6b60de..1a749cf 100644 (file)
 #define _M68K_BLINKEN_H
 
 #include <asm/setup.h>
+#include <asm/io.h>
 
 #define HP300_LEDS             0xf001ffff
 
-static __inline__ void blinken_leds(int x)
+extern unsigned char ledstate;
+
+static __inline__ void blinken_leds(int on, int off)
 {
-  if (MACH_IS_HP300)
-  {
-    *((volatile unsigned char *)HP300_LEDS) = (x);
-  }
+       if (MACH_IS_HP300)
+       {
+               ledstate |= on;
+               ledstate &= ~off;
+               out_8(HP300_LEDS, ~ledstate);
+       }
 }
 
 #endif
index c74ad77..5bc0577 100644 (file)
@@ -12,29 +12,8 @@ typedef struct {
 
 #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
- * HARDIRQ_MASK: 0x0000ff00
- * SOFTIRQ_MASK: 0x00ff0000
- */
-
-#define PREEMPT_BITS   8
-#define SOFTIRQ_BITS   8
 #define HARDIRQ_BITS   8
 
-#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
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 */
index 8948746..1144209 100644 (file)
@@ -4,6 +4,8 @@
 #ifndef _ASM_MC146818RTC_H
 #define _ASM_MC146818RTC_H
 
+#include <linux/config.h>
+
 #ifdef CONFIG_ATARI
 /* RTC in Atari machines */
 
index 7a05262..b87f2f2 100644 (file)
@@ -7,10 +7,6 @@
 #define _ASMm68k_TIMEX_H
 
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
-#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)
 
 typedef unsigned long cycles_t;
 
index dc8195e..92cf102 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _M68K_CHECKSUM_H
 #define _M68K_CHECKSUM_H
 
+#include <linux/in6.h>
+
 /*
  * computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit)
index 8d8861b..16f32cc 100644 (file)
@@ -22,7 +22,7 @@
 #define        MCF_MBAR2       0x80000000
 #define        MCF_IPSBAR      0x40000000
 
-#ifdef CONFIG_M5282
+#if defined(CONFIG_M527x) || defined(CONFIG_M528x)
 #undef MCF_MBAR
 #define        MCF_MBAR        MCF_IPSBAR
 #endif
 #define        MCF_CLK         66000000
 #elif defined(CONFIG_CLOCK_70MHz)
 #define        MCF_CLK         70000000
+#elif defined(CONFIG_CLOCK_100MHz)
+#define        MCF_CLK         100000000
 #elif defined(CONFIG_CLOCK_140MHz)
 #define        MCF_CLK         140000000
+#elif defined(CONFIG_CLOCK_150MHz)
+#define        MCF_CLK         150000000
+#elif defined(CONFIG_CLOCK_166MHz)
+#define        MCF_CLK         166000000
 #else
 #error "Don't know what your ColdFire CPU clock frequency is??"
 #endif
@@ -70,7 +76,7 @@
  *     One some ColdFire family members the bus clock (used by internal
  *     peripherals) is not the same as the CPU clock.
  */
-#ifdef CONFIG_M5249
+#if defined(CONFIG_M5249) || defined(CONFIG_M527x)
 #define        MCF_BUSCLK      (MCF_CLK / 2)
 #else
 #define        MCF_BUSCLK      MCF_CLK
index d546916..e3a9762 100644 (file)
@@ -1,14 +1,13 @@
 #ifndef _M68KNOMMU_DELAY_H
 #define _M68KNOMMU_DELAY_H
 
-#include <asm/param.h>
-
 /*
  * Copyright (C) 1994 Hamish Macdonald
- *
- * Delay routines, using a pre-computed "loops_per_second" value.
+ * Copyright (C) 2004 Greg Ungerer <gerg@snapgear.com>
  */
 
+#include <asm/param.h>
+
 extern __inline__ void __delay(unsigned long loops)
 {
 #if defined(CONFIG_COLDFIRE)
@@ -34,35 +33,27 @@ extern __inline__ void __delay(unsigned long loops)
 }
 
 /*
- * Use only for very small delays ( < 1 msec).  Should probably use a
- * lookup table, really, as the multiplications take much too long with
- * short delays.  This is a "reasonable" implementation, though (and the
- * first constant multiplications gets optimized away if the delay is
- * a constant)  
+ *     Ideally we use a 32*32->64 multiply to calculate the number of
+ *     loop iterations, but the older standard 68k and ColdFire do not
+ *     have this instruction. So for them we have a clsoe approximation
+ *     loop using 32*32->32 multiplies only. This calculation based on
+ *     the ARM version of delay.
+ *
+ *     We want to implement:
+ *
+ *     loops = (usecs * 0x10c6 * HZ * loops_per_jiffy) / 2^32
  */
 
+#define        HZSCALE         (268435456 / (1000000/HZ))
+
 extern unsigned long loops_per_jiffy;
 
-extern __inline__ void udelay(unsigned long usecs)
+extern __inline__ void _udelay(unsigned long usecs)
 {
-#ifdef CONFIG_M68332
-        usecs *= 0x000010c6;       
-       __asm__ __volatile__ ("mulul %1,%0:%2"
-                    : "=d" (usecs)
-                  : "d" (usecs),
-                   "d" (loops_per_jiffy*HZ));
-       __delay(usecs);
-
-#elif defined(CONFIG_M68328) || defined(CONFIG_M68EZ328) || \
-               defined(CONFIG_COLDFIRE) || defined(CONFIG_M68360) || \
-               defined(CONFIG_M68VZ328)
-       register unsigned long full_loops, part_loops;
-
-       full_loops = ((usecs * HZ) / 1000000) * loops_per_jiffy;
-       usecs %= (1000000 / HZ);
-       part_loops = (usecs * HZ * loops_per_jiffy) / 1000000;
-
-       __delay(full_loops + part_loops);
+#if defined(CONFIG_M68328) || defined(CONFIG_M68EZ328) || \
+    defined(CONFIG_M68VZ328) || defined(CONFIG_M68360) || \
+    defined(CONFIG_COLDFIRE)
+       __delay((((usecs * HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6);
 #else
        unsigned long tmp;
 
@@ -74,4 +65,12 @@ extern __inline__ void udelay(unsigned long usecs)
 #endif
 }
 
+/*
+ *     Moved the udelay() function into library code, no longer inlined.
+ *     I had to change the algorithm because we are overflowing now on
+ *     the faster ColdFire parts. The code is a little biger, so it makes
+ *     sense to library it.
+ */
+extern void udelay(unsigned long usecs);
+
 #endif /* defined(_M68KNOMMU_DELAY_H) */
index 840eac2..79327f5 100644 (file)
@@ -13,29 +13,8 @@ typedef struct {
 
 #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
- * HARDIRQ_MASK: 0x0000ff00
- * SOFTIRQ_MASK: 0x00ff0000
- */
-
-#define PREEMPT_BITS   8
-#define SOFTIRQ_BITS   8
 #define HARDIRQ_BITS   8
 
-#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
index 654bf15..e14f03e 100644 (file)
@@ -102,6 +102,8 @@ static inline void io_insl(unsigned int addr, void *buf, int len)
                *bp++ = _swapl(*ap);
 }
 
+#define mmiowb()
+
 /*
  *     make the short names macros so specific devices
  *     can override them as required
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 */
index 98fadce..350c609 100644 (file)
@@ -21,7 +21,7 @@
 #define        MCFDMA_BASE1            0x240           /* Base address of DMA 1 */
 #elif defined(CONFIG_M5272)
 #define        MCFDMA_BASE0            0x0e0           /* Base address of DMA 0 */
-#elif defined(CONFIG_M5282)
+#elif defined(CONFIG_M527x) || defined(CONFIG_M528x)
 /* These are relative to the IPSBAR, not MBAR */
 #define        MCFDMA_BASE0            0x100           /* Base address of DMA 0 */
 #define        MCFDMA_BASE1            0x140           /* Base address of DMA 1 */
index 76ccfc2..4cc2e9f 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/config.h>
 
 /*
- *     Get address specific defines for the 5282.
+ *     Get address specific defines for the 5270/5271 and 5280/5282.
  */
 #define        MCFPIT_BASE1            0x00150000      /* Base address of TIMER1 */
 #define        MCFPIT_BASE2            0x00160000      /* Base address of TIMER2 */
index 27d6cb6..522e513 100644 (file)
@@ -15,7 +15,8 @@
 #include <linux/config.h>
 
 /*
- *     Include 5204, 5206, 5249, 5272, 5282, 5307 or 5407 specific addresses.
+ *     Include 5204, 5206/e, 5249, 5270/5271, 5272, 5280/5282, 5307 or
+ *     5407 specific addresses.
  */
 #if defined(CONFIG_M5204)
 #include <asm/m5204sim.h>
 #include <asm/m5206sim.h>
 #elif defined(CONFIG_M5249)
 #include <asm/m5249sim.h>
+#elif defined(CONFIG_M527x)
+#include <asm/m527xsim.h>
 #elif defined(CONFIG_M5272)
 #include <asm/m5272sim.h>
-#elif defined(CONFIG_M5282)
-#include <asm/m5282sim.h>
+#elif defined(CONFIG_M528x)
+#include <asm/m528xsim.h>
 #elif defined(CONFIG_M5307)
 #include <asm/m5307sim.h>
 #elif defined(CONFIG_M5407)
index 9107322..54d4a85 100644 (file)
@@ -29,7 +29,7 @@
 #define        MCFUART_BASE1           0x140           /* Base address of UART1 */
 #define        MCFUART_BASE2           0x180           /* Base address of UART2 */
 #endif
-#elif defined(CONFIG_M5282)
+#elif defined(CONFIG_M527x) || defined(CONFIG_M528x)
 #define MCFUART_BASE1          0x200           /* Base address of UART1 */
 #define MCFUART_BASE2          0x240           /* Base address of UART2 */
 #define MCFUART_BASE3          0x280           /* Base address of UART3 */
index 15eea42..2b45645 100644 (file)
@@ -1,6 +1,5 @@
 
 #include <linux/config.h>
-#include <asm/shglcore.h>
 
 /* This handles the memory map.. */
 
@@ -45,7 +44,4 @@
 #ifdef CONFIG_M68EN302
 #define PAGE_OFFSET_RAW                0x00000000
 #endif
-#ifdef CONFIG_SHGLCORE
-#define PAGE_OFFSET_RAW                SHGLCORE_RAM_BANK_0_ADDR 
-#endif
 
index 734960d..3f57d5d 100644 (file)
@@ -3,38 +3,11 @@
 
 #include <linux/config.h>
 
-#ifndef HZ
-#ifdef CONFIG_COLDFIRE
 #if defined(CONFIG_CLEOPATRA)
-#define HZ 1000
-#else
-#define HZ 100
-#endif
-#endif
-#ifdef CONFIG_M68EN302
-#define HZ 100
-#endif
-#ifdef CONFIG_M68328
-#define HZ 100
+#define        HZ 1000
 #endif
-#ifdef CONFIG_M68EZ328
-#define HZ 100
-#endif
-#ifdef CONFIG_UCSIMM
-#define HZ 100
-#endif
-
-#ifdef CONFIG_M68VZ328
-#define HZ 100
-#endif
-
-#ifdef CONFIG_SHGLCORE
-#define HZ 50
-#endif
-#ifdef CONFIG_M68360
-#define HZ 100
-#endif
-
+#ifndef HZ
+#define        HZ 100
 #endif
 
 #ifdef __KERNEL__
index e12f9eb..ce3f0b0 100644 (file)
@@ -257,6 +257,19 @@ cmpxchg(volatile int *p, int old, int new)
         jmp (%a0);                     \
         ");                            \
 })
+#elif defined(CONFIG_M528x)
+/*
+ * The MCF528x has a bit (SOFTRST) in memory (Reset Control Register RCR),
+ * that when set, resets the MCF528x.
+ */
+#define HARD_RESET_NOW() \
+({                                             \
+       unsigned char volatile *reset;          \
+       asm("move.w     #0x2700, %sr");         \
+       reset = ((volatile unsigned short *)(MCF_IPSBAR + 0x110000));   \
+       while(1)                                \
+       *reset |= (0x01 << 7);\
+})
 #else
 #define HARD_RESET_NOW() ({            \
         asm("                          \
index f45b12a..dcdc2b3 100644 (file)
 
 #ifdef __KERNEL__
 
+/*
+ * Size of kernel stack for each process. This must be a power of 2...
+ */
+#define THREAD_SIZE            8192    /* 2 pages */
+
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -45,12 +51,6 @@ struct thread_info {
 #define init_stack             (init_thread_union.stack)
 
 
-/*
- * Size of kernel stack for each process. This must be a power of 2...
- */
-#define THREAD_SIZE            8192    /* 2 pages */
-
-
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
index 8e81636..f3eda9d 100644 (file)
 #define _ACAST64_              (_ATYPE64_)             /* do _not_ narrow */
 #endif
 
-/*
- * Memory segments (32bit kernel mode addresses)
- * These are the traditional names used in the 32-bit universe.
- */
-#define KUSEG                  0x00000000
-#define KSEG0                  0x80000000
-#define KSEG1                  0xa0000000
-#define KSEG2                  0xc0000000
-#define KSEG3                  0xe0000000
-
 /*
  * Returns the kernel segment base of a given address
  */
 #define CPHYSADDR(a)           ((_ACAST32_ (a)) & 0x1fffffff)
 #define XPHYSADDR(a)            ((_ACAST64_ (a)) & 0x000000ffffffffff)
 
-/*
- * Map an address to a certain kernel segment
- */
-#define KSEG0ADDR(a)           (CPHYSADDR(a) | KSEG0)
-#define KSEG1ADDR(a)           (CPHYSADDR(a) | KSEG1)
-#define KSEG2ADDR(a)           (CPHYSADDR(a) | KSEG2)
-#define KSEG3ADDR(a)           (CPHYSADDR(a) | KSEG3)
-
-#define CKSEG0ADDR(a)          (CPHYSADDR(a) | CKSEG0)
-#define CKSEG1ADDR(a)          (CPHYSADDR(a) | CKSEG1)
-#define CKSEG2ADDR(a)          (CPHYSADDR(a) | CKSEG2)
-#define CKSEG3ADDR(a)          (CPHYSADDR(a) | CKSEG3)
+#ifdef CONFIG_MIPS64
 
 /*
  * Memory segments (64bit kernel mode addresses)
 #define CKSSEG                 0xffffffffc0000000
 #define CKSEG3                 0xffffffffe0000000
 
+#define CKSEG0ADDR(a)          (CPHYSADDR(a) | CKSEG0)
+#define CKSEG1ADDR(a)          (CPHYSADDR(a) | CKSEG1)
+#define CKSEG2ADDR(a)          (CPHYSADDR(a) | CKSEG2)
+#define CKSEG3ADDR(a)          (CPHYSADDR(a) | CKSEG3)
+
+#else
+
+#define CKSEG0ADDR(a)          (CPHYSADDR(a) | KSEG0)
+#define CKSEG1ADDR(a)          (CPHYSADDR(a) | KSEG1)
+#define CKSEG2ADDR(a)          (CPHYSADDR(a) | KSEG2)
+#define CKSEG3ADDR(a)          (CPHYSADDR(a) | KSEG3)
+
+/*
+ * Map an address to a certain kernel segment
+ */
+#define KSEG0ADDR(a)           (CPHYSADDR(a) | KSEG0)
+#define KSEG1ADDR(a)           (CPHYSADDR(a) | KSEG1)
+#define KSEG2ADDR(a)           (CPHYSADDR(a) | KSEG2)
+#define KSEG3ADDR(a)           (CPHYSADDR(a) | KSEG3)
+
+/*
+ * Memory segments (32bit kernel mode addresses)
+ * These are the traditional names used in the 32-bit universe.
+ */
+#define KUSEG                  0x00000000
+#define KSEG0                  0x80000000
+#define KSEG1                  0xa0000000
+#define KSEG2                  0xc0000000
+#define KSEG3                  0xe0000000
+
+#define CKUSEG                 0x00000000
+#define CKSEG0                 0x80000000
+#define CKSEG1                 0xa0000000
+#define CKSEG2                 0xc0000000
+#define CKSEG3                 0xe0000000
+
+#endif
+
 /*
  * Cache modes for XKPHYS address conversion macros
  */
index 1d927d0..ac8823d 100644 (file)
@@ -12,8 +12,8 @@
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
 
-       .macro  fpu_save_double thread tmp=t0
-       cfc1    \tmp,  fcr31
+       .macro  fpu_save_double thread status tmp1=t0 tmp2
+       cfc1    \tmp1,  fcr31
        sdc1    $f0,  THREAD_FPR0(\thread)
        sdc1    $f2,  THREAD_FPR2(\thread)
        sdc1    $f4,  THREAD_FPR4(\thread)
@@ -30,7 +30,7 @@
        sdc1    $f26, THREAD_FPR26(\thread)
        sdc1    $f28, THREAD_FPR28(\thread)
        sdc1    $f30, THREAD_FPR30(\thread)
-       sw      \tmp, THREAD_FCR31(\thread)
+       sw      \tmp1, THREAD_FCR31(\thread)
        .endm
 
        .macro  fpu_save_single thread tmp=t0
index 10b71cc..bbed355 100644 (file)
@@ -15,6 +15,7 @@
 
        .macro  fpu_save_16even thread tmp=t0
        cfc1    \tmp, fcr31
+       sdc1    $f0,  THREAD_FPR0(\thread)
        sdc1    $f2,  THREAD_FPR2(\thread)
        sdc1    $f4,  THREAD_FPR4(\thread)
        sdc1    $f6,  THREAD_FPR6(\thread)
        sdc1    $f31, THREAD_FPR31(\thread)
        .endm
 
+       .macro  fpu_save_double thread status tmp1 tmp2
+       sll     \tmp2, \tmp1, 5
+       bgez    \tmp2, 2f
+       fpu_save_16odd \thread
+2:
+       fpu_save_16even \thread \tmp1                   # clobbers t1
+       .endm
+
        .macro  fpu_restore_16even thread tmp=t0
        lw      \tmp, THREAD_FCR31(\thread)
        ldc1    $f0,  THREAD_FPR0(\thread)
        ldc1    $f31, THREAD_FPR31(\thread)
        .endm
 
+       .macro  fpu_restore_double thread tmp
+       mfc0    t0, CP0_STATUS
+       sll     t1, t0, 5
+       bgez    t1, 1f                          # 16 register mode?
+
+       fpu_restore_16odd a0
+1:     fpu_restore_16even a0, t0               # clobbers t0
+       .endm
+
        .macro  cpu_save_nonscratch thread
        LONG_S  s0, THREAD_REG16(\thread)
        LONG_S  s1, THREAD_REG17(\thread)
index cb06e89..3f41f32 100644 (file)
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>             /* sigh ... */
+#include <asm/cpu-features.h>
 
 #if (_MIPS_SZLONG == 32)
 #define SZLONG_LOG 5
 #define SZLONG_MASK 31UL
-#define __LL   "ll"
-#define __SC   "sc"
+#define __LL   "ll     "
+#define __SC   "sc     "
 #define cpu_to_lelongp(x) cpu_to_le32p((__u32 *) (x)) 
 #elif (_MIPS_SZLONG == 64)
 #define SZLONG_LOG 6
 #define SZLONG_MASK 63UL
-#define __LL   "lld"
-#define __SC   "scd"
+#define __LL   "lld    "
+#define __SC   "scd    "
 #define cpu_to_lelongp(x) cpu_to_le64p((__u64 *) (x)) 
 #endif
 
 #ifdef __KERNEL__
 
+#include <asm/interrupt.h>
 #include <asm/sgidefs.h>
-#include <asm/system.h>
+#include <asm/war.h>
 
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  * Only disable interrupt for kernel mode stuff to keep usermode stuff
  * that dares to use kernel include files alive.
  */
+
 #define __bi_flags                     unsigned long flags
-#define __bi_cli()                     local_irq_disable()
-#define __bi_save_flags(x)             local_save_flags(x)
 #define __bi_local_irq_save(x)         local_irq_save(x)
 #define __bi_local_irq_restore(x)      local_irq_restore(x)
 #else
 #define __bi_flags
-#define __bi_cli()
-#define __bi_save_flags(x)
 #define __bi_local_irq_save(x)
 #define __bi_local_irq_restore(x)
 #endif /* __KERNEL__ */
 
-#ifdef CONFIG_CPU_HAS_LLSC
-
-/*
- * These functions for MIPS ISA > 1 are interrupt and SMP proof and
- * interrupt friendly
- */
-
 /*
  * set_bit - Atomically set a bit in memory
  * @nr: the bit to set
@@ -78,13 +70,33 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
        unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
        unsigned long temp;
 
-       __asm__ __volatile__(
-               "1:\t" __LL "\t%0, %1\t\t# set_bit\n\t"
-               "or\t%0, %2\n\t"
-               __SC "\t%0, %1\n\t"
-               "beqz\t%0, 1b"
+       if (cpu_has_llsc && R10000_LLSC_WAR) {
+               __asm__ __volatile__(
+               "1:     " __LL "%0, %1                  # set_bit       \n"
+               "       or      %0, %2                                  \n"
+               "       "__SC   "%0, %1                                 \n"
+               "       beqzl   %0, 1b                                  \n"
                : "=&r" (temp), "=m" (*m)
                : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
+       } else if (cpu_has_llsc) {
+               __asm__ __volatile__(
+               "1:     " __LL "%0, %1                  # set_bit       \n"
+               "       or      %0, %2                                  \n"
+               "       "__SC   "%0, %1                                 \n"
+               "       beqz    %0, 1b                                  \n"
+               : "=&r" (temp), "=m" (*m)
+               : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
+       } else {
+               volatile unsigned long *a = addr;
+               unsigned long mask;
+               __bi_flags;
+
+               a += nr >> SZLONG_LOG;
+               mask = 1 << (nr & SZLONG_MASK);
+               __bi_local_irq_save(flags);
+               *a |= mask;
+               __bi_local_irq_restore(flags);
+       }
 }
 
 /*
@@ -118,13 +130,33 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
        unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
        unsigned long temp;
 
-       __asm__ __volatile__(
-               "1:\t" __LL "\t%0, %1\t\t# clear_bit\n\t"
-               "and\t%0, %2\n\t"
-               __SC "\t%0, %1\n\t"
-               "beqz\t%0, 1b\n\t"
+       if (cpu_has_llsc && R10000_LLSC_WAR) {
+               __asm__ __volatile__(
+               "1:     " __LL "%0, %1                  # clear_bit     \n"
+               "       and     %0, %2                                  \n"
+               "       " __SC "%0, %1                                  \n"
+               "       beqzl   %0, 1b                                  \n"
+               : "=&r" (temp), "=m" (*m)
+               : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m));
+       } else if (cpu_has_llsc) {
+               __asm__ __volatile__(
+               "1:     " __LL "%0, %1                  # clear_bit     \n"
+               "       and     %0, %2                                  \n"
+               "       " __SC "%0, %1                                  \n"
+               "       beqz    %0, 1b                                  \n"
                : "=&r" (temp), "=m" (*m)
                : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m));
+       } else {
+               volatile unsigned long *a = addr;
+               unsigned long mask;
+               __bi_flags;
+
+               a += nr >> SZLONG_LOG;
+               mask = 1 << (nr & SZLONG_MASK);
+               __bi_local_irq_save(flags);
+               *a &= ~mask;
+               __bi_local_irq_restore(flags);
+       }
 }
 
 /*
@@ -154,16 +186,39 @@ static inline void __clear_bit(unsigned long nr, volatile unsigned long * addr)
  */
 static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
 {
-       unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
-       unsigned long temp;
+       if (cpu_has_llsc && R10000_LLSC_WAR) {
+               unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
+               unsigned long temp;
 
-       __asm__ __volatile__(
-               "1:\t" __LL "\t%0, %1\t\t# change_bit\n\t"
-               "xor\t%0, %2\n\t"
-               __SC "\t%0, %1\n\t"
-               "beqz\t%0, 1b"
+               __asm__ __volatile__(
+               "1:     " __LL "%0, %1          # change_bit    \n"
+               "       xor     %0, %2                          \n"
+               "       "__SC   "%0, %1                         \n"
+               "       beqzl   %0, 1b                          \n"
                : "=&r" (temp), "=m" (*m)
                : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
+       } else if (cpu_has_llsc) {
+               unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
+               unsigned long temp;
+
+               __asm__ __volatile__(
+               "1:     " __LL "%0, %1          # change_bit    \n"
+               "       xor     %0, %2                          \n"
+               "       "__SC   "%0, %1                         \n"
+               "       beqz    %0, 1b                          \n"
+               : "=&r" (temp), "=m" (*m)
+               : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
+       } else {
+               volatile unsigned long *a = addr;
+               unsigned long mask;
+               __bi_flags;
+
+               a += nr >> SZLONG_LOG;
+               mask = 1 << (nr & SZLONG_MASK);
+               __bi_local_irq_save(flags);
+               *a ^= mask;
+               __bi_local_irq_restore(flags);
+       }
 }
 
 /*
@@ -193,25 +248,59 @@ static inline void __change_bit(unsigned long nr, volatile unsigned long * addr)
 static inline int test_and_set_bit(unsigned long nr,
        volatile unsigned long *addr)
 {
-       unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
-       unsigned long temp, res;
-
-       __asm__ __volatile__(
-               ".set\tnoreorder\t\t# test_and_set_bit\n"
-               "1:\t" __LL "\t%0, %1\n\t"
-               "or\t%2, %0, %3\n\t"
-               __SC "\t%2, %1\n\t"
-               "beqz\t%2, 1b\n\t"
-               " and\t%2, %0, %3\n\t"
+       if (cpu_has_llsc && R10000_LLSC_WAR) {
+               unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
+               unsigned long temp, res;
+
+               __asm__ __volatile__(
+               "1:     " __LL "%0, %1          # test_and_set_bit      \n"
+               "       or      %2, %0, %3                              \n"
+               "       " __SC  "%2, %1                                 \n"
+               "       beqzl   %2, 1b                                  \n"
+               "       and     %2, %0, %3                              \n"
 #ifdef CONFIG_SMP
-               "sync\n\t"
+               "sync                                                   \n"
+#endif
+               : "=&r" (temp), "=m" (*m), "=&r" (res)
+               : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
+               : "memory");
+
+               return res != 0;
+       } else if (cpu_has_llsc) {
+               unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
+               unsigned long temp, res;
+
+               __asm__ __volatile__(
+               "       .set    noreorder       # test_and_set_bit      \n"
+               "1:     " __LL "%0, %1                                  \n"
+               "       or      %2, %0, %3                              \n"
+               "       " __SC  "%2, %1                                 \n"
+               "       beqz    %2, 1b                                  \n"
+               "        and    %2, %0, %3                              \n"
+#ifdef CONFIG_SMP
+               "sync                                                   \n"
 #endif
                ".set\treorder"
                : "=&r" (temp), "=m" (*m), "=&r" (res)
                : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
                : "memory");
 
-       return res != 0;
+               return res != 0;
+       } else {
+               volatile unsigned long *a = addr;
+               unsigned long mask;
+               int retval;
+               __bi_flags;
+
+               a += nr >> SZLONG_LOG;
+               mask = 1 << (nr & SZLONG_MASK);
+               __bi_local_irq_save(flags);
+               retval = (mask & *a) != 0;
+               *a |= mask;
+               __bi_local_irq_restore(flags);
+
+               return retval;
+       }
 }
 
 /*
@@ -249,26 +338,61 @@ static inline int __test_and_set_bit(unsigned long nr,
 static inline int test_and_clear_bit(unsigned long nr,
        volatile unsigned long *addr)
 {
-       unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
-       unsigned long temp, res;
-
-       __asm__ __volatile__(
-               ".set\tnoreorder\t\t# test_and_clear_bit\n"
-               "1:\t" __LL "\t%0, %1\n\t"
-               "or\t%2, %0, %3\n\t"
-               "xor\t%2, %3\n\t"
-               __SC "\t%2, %1\n\t"
-               "beqz\t%2, 1b\n\t"
-               " and\t%2, %0, %3\n\t"
+       if (cpu_has_llsc && R10000_LLSC_WAR) {
+               unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
+               unsigned long temp, res;
+
+               __asm__ __volatile__(
+               "1:     " __LL  "%0, %1         # test_and_clear_bit    \n"
+               "       or      %2, %0, %3                              \n"
+               "       xor     %2, %3                                  \n"
+                       __SC    "%2, %1                                 \n"
+               "       beqzl   %2, 1b                                  \n"
+               "       and     %2, %0, %3                              \n"
 #ifdef CONFIG_SMP
-               "sync\n\t"
+               "       sync                                            \n"
 #endif
-               ".set\treorder"
                : "=&r" (temp), "=m" (*m), "=&r" (res)
                : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
                : "memory");
 
-       return res != 0;
+               return res != 0;
+       } else if (cpu_has_llsc) {
+               unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
+               unsigned long temp, res;
+
+               __asm__ __volatile__(
+               "       .set    noreorder       # test_and_clear_bit    \n"
+               "1:     " __LL  "%0, %1                                 \n"
+               "       or      %2, %0, %3                              \n"
+               "       xor     %2, %3                                  \n"
+                       __SC    "%2, %1                                 \n"
+               "       beqz    %2, 1b                                  \n"
+               "        and    %2, %0, %3                              \n"
+#ifdef CONFIG_SMP
+               "       sync                                            \n"
+#endif
+               "       .set    reorder                                 \n"
+               : "=&r" (temp), "=m" (*m), "=&r" (res)
+               : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
+               : "memory");
+
+               return res != 0;
+       } else {
+               volatile unsigned long *a = addr;
+               unsigned long mask;
+               int retval;
+               __bi_flags;
+
+               a += nr >> SZLONG_LOG;
+               mask = 1 << (nr & SZLONG_MASK);
+               __bi_local_irq_save(flags);
+               retval = (mask & *a) != 0;
+               *a &= ~mask;
+               __bi_local_irq_restore(flags);
+
+               return retval;
+       }
 }
 
 /*
@@ -306,322 +430,88 @@ static inline int __test_and_clear_bit(unsigned long nr,
 static inline int test_and_change_bit(unsigned long nr,
        volatile unsigned long *addr)
 {
-       unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
-       unsigned long temp, res;
-
-       __asm__ __volatile__(
-               ".set\tnoreorder\t\t# test_and_change_bit\n"
-               "1:\t" __LL "\t%0, %1\n\t"
-               "xor\t%2, %0, %3\n\t"
-               __SC "\t%2, %1\n\t"
-               "beqz\t%2, 1b\n\t"
-               " and\t%2, %0, %3\n\t"
+       if (cpu_has_llsc && R10000_LLSC_WAR) {
+               unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
+               unsigned long temp, res;
+
+               __asm__ __volatile__(
+               "1:     " __LL  " %0, %1        # test_and_change_bit   \n"
+               "       xor     %2, %0, %3                              \n"
+               "       "__SC   "%2, %1                                 \n"
+               "       beqzl   %2, 1b                                  \n"
+               "       and     %2, %0, %3                              \n"
 #ifdef CONFIG_SMP
-               "sync\n\t"
+               "       sync                                            \n"
 #endif
-               ".set\treorder"
                : "=&r" (temp), "=m" (*m), "=&r" (res)
                : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
                : "memory");
 
-       return res != 0;
-}
-
-/*
- * __test_and_change_bit - Change a bit and return its old value
- * @nr: Bit to change
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * 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_change_bit(unsigned long nr,
-       volatile unsigned long *addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
-       int retval;
-
-       a += (nr >> SZLONG_LOG);
-       mask = 1UL << (nr & SZLONG_MASK);
-       retval = ((mask & *a) != 0);
-       *a ^= mask;
-
-       return retval;
-}
-
-#else /* MIPS I */
-
-/*
- * 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(unsigned long nr, volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
-       __bi_flags;
-
-       a += nr >> SZLONG_LOG;
-       mask = 1 << (nr & SZLONG_MASK);
-       __bi_local_irq_save(flags);
-       *a |= mask;
-       __bi_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(unsigned long nr, volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
-
-       a += nr >> SZLONG_LOG;
-       mask = 1 << (nr & SZLONG_MASK);
-       *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(unsigned long nr, volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
-       __bi_flags;
+               return res != 0;
+       } else if (cpu_has_llsc) {
+               unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
+               unsigned long temp, res;
+
+               __asm__ __volatile__(
+               "       .set    noreorder       # test_and_change_bit   \n"
+               "1:     " __LL  " %0, %1                                \n"
+               "       xor     %2, %0, %3                              \n"
+               "       "__SC   "\t%2, %1                               \n"
+               "       beqz    %2, 1b                                  \n"
+               "        and    %2, %0, %3                              \n"
+#ifdef CONFIG_SMP
+               "       sync                                            \n"
+#endif
+               "       .set    reorder                                 \n"
+               : "=&r" (temp), "=m" (*m), "=&r" (res)
+               : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
+               : "memory");
 
-       a += nr >> SZLONG_LOG;
-       mask = 1 << (nr & SZLONG_MASK);
-       __bi_local_irq_save(flags);
-       *a &= ~mask;
-       __bi_local_irq_restore(flags);
-}
+               return res != 0;
+       } else {
+               volatile unsigned long *a = addr;
+               unsigned long mask, retval;
+               __bi_flags;
 
-static inline void __clear_bit(unsigned long nr, volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
+               a += nr >> SZLONG_LOG;
+               mask = 1 << (nr & SZLONG_MASK);
+               __bi_local_irq_save(flags);
+               retval = (mask & *a) != 0;
+               *a ^= mask;
+               __bi_local_irq_restore(flags);
 
-       a += nr >> SZLONG_LOG;
-       mask = 1 << (nr & SZLONG_MASK);
-       *a &= ~mask;
+               return retval;
+       }
 }
 
 /*
- * change_bit - Toggle a bit in memory
+ * __test_and_change_bit - Change a bit and return its old value
  * @nr: Bit to change
- * @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(unsigned long nr, volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
-       __bi_flags;
-
-       a += nr >> SZLONG_LOG;
-       mask = 1 << (nr & SZLONG_MASK);
-       __bi_local_irq_save(flags);
-       *a ^= mask;
-       __bi_local_irq_restore(flags);
-}
-
-/*
- * __change_bit - Toggle a bit in memory
- * @nr: the bit to change
- * @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(unsigned long nr, volatile unsigned long * addr)
-{
-       unsigned long * m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
-
-       *m ^= 1UL << (nr & SZLONG_MASK);
-}
-
-/*
- * 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(unsigned long nr,
-       volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
-       int retval;
-       __bi_flags;
-
-       a += nr >> SZLONG_LOG;
-       mask = 1 << (nr & SZLONG_MASK);
-       __bi_local_irq_save(flags);
-       retval = (mask & *a) != 0;
-       *a |= mask;
-       __bi_local_irq_restore(flags);
-
-       return retval;
-}
-
-/*
- * __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(unsigned long nr,
+static inline int __test_and_change_bit(unsigned long nr,
        volatile unsigned long *addr)
 {
        volatile unsigned long *a = addr;
        unsigned long mask;
        int retval;
 
-       a += nr >> SZLONG_LOG;
-       mask = 1 << (nr & SZLONG_MASK);
-       retval = (mask & *a) != 0;
-       *a |= mask;
-
-       return retval;
-}
-
-/*
- * test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to clear
- * @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(unsigned long nr,
-       volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
-       int retval;
-       __bi_flags;
-
-       a += nr >> SZLONG_LOG;
-       mask = 1 << (nr & SZLONG_MASK);
-       __bi_local_irq_save(flags);
-       retval = (mask & *a) != 0;
-       *a &= ~mask;
-       __bi_local_irq_restore(flags);
-
-       return retval;
-}
-
-/*
- * __test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to clear
- * @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(unsigned long nr,
-       volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
-       int retval;
-
        a += (nr >> SZLONG_LOG);
        mask = 1UL << (nr & SZLONG_MASK);
        retval = ((mask & *a) != 0);
-       *a &= ~mask;
-
-       return retval;
-}
-
-/*
- * test_and_change_bit - Change a bit and return its old value
- * @nr: Bit to change
- * @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(unsigned long nr,
-       volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask, retval;
-       __bi_flags;
-
-       a += nr >> SZLONG_LOG;
-       mask = 1 << (nr & SZLONG_MASK);
-       __bi_local_irq_save(flags);
-       retval = (mask & *a) != 0;
-       *a ^= mask;
-       __bi_local_irq_restore(flags);
-
-       return retval;
-}
-
-/*
- * __test_and_change_bit - Change a bit and return its old value
- * @nr: Bit to change
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * 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_change_bit(unsigned long nr,
-       volatile unsigned long * addr)
-{
-       volatile unsigned long *a = addr;
-       unsigned long mask;
-       int retval;
-
-       a += (nr >> SZLONG_LOG);
-       mask = 1 << (nr & SZLONG_MASK);
-       retval = (mask & *a) != 0;
        *a ^= mask;
 
        return retval;
 }
 
 #undef __bi_flags
-#undef __bi_cli
-#undef __bi_save_flags
+#undef __bi_local_irq_save
 #undef __bi_local_irq_restore
 
-#endif /* MIPS I */
-
 /*
  * test_bit - Determine whether a bit is set
  * @nr: bit number to test
index 88ca4d5..38b2116 100644 (file)
@@ -132,10 +132,10 @@ static inline void *compat_ptr(compat_uptr_t uptr)
 
 static inline void *compat_alloc_user_space(long len)
 {
-       unsigned long sp = (unsigned long) current_thread_info() +
-                           THREAD_SIZE - 32;
+       struct pt_regs *regs = (struct pt_regs *)
+               ((unsigned long) current_thread_info() + THREAD_SIZE - 32) - 1;
 
-       return (void *) (sp - len);
+       return (void *) (regs->regs[29] - len);
 }
 
 #endif /* _ASM_COMPAT_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 */
index 1bc8758..ea559a3 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __ASM_CPU_FEATURES_H
 #define __ASM_CPU_FEATURES_H
 
+#include <asm/cpu.h>
+#include <asm/cpu-info.h>
 #include <cpu-feature-overrides.h>
 
 /*
 #define cpu_has_dc_aliases     (cpu_data[0].dcache.flags & MIPS_CACHE_ALIASES)
 #endif
 #ifndef cpu_has_ic_fills_f_dc
-#define cpu_has_ic_fills_f_dc  (cpu_data[0].dcache.flags & MIPS_CACHE_IC_F_DC)
+#define cpu_has_ic_fills_f_dc  (cpu_data[0].icache.flags & MIPS_CACHE_IC_F_DC)
+#endif
+
+/*
+ * Certain CPUs may throw bizarre exceptions if not the whole cacheline
+ * contains valid instructions.  For these we ensure proper alignment of
+ * signal trampolines and pad them to the size of a full cache lines with
+ * nops.  This is also used in structure definitions so can't be a test macro
+ * like the others.
+ */
+#ifndef PLAT_TRAMPOLINE_STUFF_LINE
+#define PLAT_TRAMPOLINE_STUFF_LINE     0UL
 #endif
 
 #ifdef CONFIG_MIPS32
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 */
index e546619..d713707 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Debug macros for run-time debugging.  Turned on/off with CONFIG_RUNTIME_DEBUG option.
+ * Debug macros for run-time debugging.
+ * Turned on/off with CONFIG_RUNTIME_DEBUG option.
  *
  * Copyright (C) 2001 MontaVista Software Inc.
  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
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 */
index 91fdf79..d0f6844 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/config.h>
 #include <linux/param.h>
 
+#include <asm/compiler.h>
+
 extern unsigned long loops_per_jiffy;
 
 static inline void __delay(unsigned long loops)
@@ -69,11 +71,13 @@ static inline void __udelay(unsigned long usecs, unsigned long lpj)
        if (sizeof(long) == 4)
                __asm__("multu\t%2, %3"
                : "=h" (usecs), "=l" (lo)
-               : "r" (usecs),"r" (lpj));
+               : "r" (usecs), "r" (lpj)
+               : GCC_REG_ACCUM);
        else if (sizeof(long) == 8)
                __asm__("dmultu\t%2, %3"
                : "=h" (usecs), "=l" (lo)
-               : "r" (usecs),"r" (lpj));
+               : "r" (usecs), "r" (lpj)
+               : GCC_REG_ACCUM);
 
        __delay(usecs);
 }
index 7e7e2ea..5f7dcf5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2000 Maciej W. Rozycki
+ * Copyright (C) 2000, 2004  Maciej W. Rozycki
  * Copyright (C) 2003 Ralf Baechle
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -11,6 +11,8 @@
 
 #if (_MIPS_SZLONG == 32)
 
+#include <asm/compiler.h>
+
 /*
  * No traps on overflows for any of these...
  */
@@ -67,7 +69,8 @@
        if (__high) \
                __asm__("divu   $0, %z2, %z3" \
                        : "=h" (__upper), "=l" (__high) \
-                       : "Jr" (__high), "Jr" (__base)); \
+                       : "Jr" (__high), "Jr" (__base) \
+                       : GCC_REG_ACCUM); \
        \
        __mod = do_div64_32(__low, __upper, __low, __base); \
        \
index 7169511..af28dc8 100644 (file)
@@ -68,4 +68,12 @@ extern int dma_is_consistent(dma_addr_t dma_addr);
 extern void dma_cache_sync(void *vaddr, size_t size,
               enum dma_data_direction direction);
 
+#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
+
+extern int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+       dma_addr_t device_addr, size_t size, int flags);
+extern void dma_release_declared_memory(struct device *dev);
+extern void * dma_mark_declared_memory_occupied(struct device *dev,
+       dma_addr_t device_addr, size_t size);
+
 #endif /* _ASM_DMA_MAPPING_H */
index 35d47a8..2b458f9 100644 (file)
  */
 #define ENOMEDIUM      159     /* No medium found */
 #define EMEDIUMTYPE    160     /* Wrong medium type */
+#define        ENOKEY          161     /* Required key not available */
+#define        EKEYEXPIRED     162     /* Key has expired */
+#define        EKEYREVOKED     163     /* Key has been revoked */
+#define        EKEYREJECTED    164     /* Key was rejected by service */
 
 #define EDQUOT         1133    /* Quota exceeded */
 
index b86291d..26b6a90 100644 (file)
@@ -14,7 +14,6 @@
 #define _ASM_FIXMAP_H
 
 #include <linux/config.h>
-#include <linux/kernel.h>
 #include <asm/page.h>
 #ifdef CONFIG_HIGHMEM
 #include <linux/threads.h>
index bbc328f..22f67d4 100644 (file)
@@ -207,6 +207,7 @@ struct gdb_regs {
  * Prototypes
  */
 
+extern int kgdb_enabled;
 void set_debug_traps(void);
 void set_async_breakpoint(unsigned long *epc);
 
index 7562703..8f535d0 100644 (file)
@@ -20,45 +20,6 @@ typedef struct {
 
 #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
-#define HARDIRQ_BITS   8
-
-#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 irq_exit()                                                     \
-do {                                                                   \
-       preempt_count() -= IRQ_EXIT_OFFSET;                     \
-       if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-               do_softirq();                                   \
-       preempt_enable_no_resched();                            \
-} while (0)
+extern void ack_bad_irq(unsigned int irq);
 
 #endif /* _ASM_HARDIRQ_H */
index 8be338b..c854d01 100644 (file)
@@ -11,8 +11,6 @@
 #include <linux/profile.h>
 #include <asm/atomic.h>
 
-extern void mask_irq(unsigned int irq);
-extern void unmask_irq(unsigned int irq);
 extern void disable_8259A_irq(unsigned int irq);
 extern void enable_8259A_irq(unsigned int irq);
 extern int i8259A_irq_pending(unsigned int irq);
index 1992aac..bb674c3 100644 (file)
@@ -4,22 +4,10 @@
  * for more details.
  *
  * This file contains the MIPS architecture specific IDE code.
- *
- * Copyright (C) 1994-1996  Linus Torvalds & authors
  */
-
 #ifndef __ASM_IDE_H
 #define __ASM_IDE_H
 
-#ifdef __KERNEL__
-
 #include <ide.h>
 
-#define __ide_mm_insw   ide_insw
-#define __ide_mm_insl   ide_insl
-#define __ide_mm_outsw  ide_outsw
-#define __ide_mm_outsl  ide_outsl
-
-#endif /* __KERNEL__ */
-
 #endif /* __ASM_IDE_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 */
index 9ec7ced..6f71420 100644 (file)
@@ -11,6 +11,7 @@
 #define _ASM_IO_H
 
 #include <linux/config.h>
+#include <linux/compiler.h>
 #include <linux/types.h>
 
 #include <asm/addrspace.h>
@@ -169,9 +170,9 @@ extern unsigned long isa_slot_offset;
 #define page_to_phys(page)     ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
 
 extern void * __ioremap(phys_t offset, phys_t size, unsigned long flags);
-extern void __iounmap(void *addr);
+extern void __iounmap(volatile void __iomem *addr);
 
-static inline void * __ioremap_mode(unsigned long offset, unsigned long size,
+static inline void * __ioremap_mode(phys_t offset, unsigned long size,
        unsigned long flags)
 {
        if (cpu_has_64bit_addresses) {
@@ -236,7 +237,7 @@ static inline void * __ioremap_mode(unsigned long offset, unsigned long size,
 #define ioremap_uncached_accelerated(offset, size)                     \
        __ioremap_mode((offset), (size), _CACHE_UNCACHED_ACCELERATED)
 
-static inline void iounmap(void *addr)
+static inline void iounmap(volatile void __iomem *addr)
 {
        if (cpu_has_64bits)
                return;
@@ -244,9 +245,12 @@ static inline void iounmap(void *addr)
        __iounmap(addr);
 }
 
-#define __raw_readb(addr)      (*(volatile unsigned char *)(addr))
-#define __raw_readw(addr)      (*(volatile unsigned short *)(addr))
-#define __raw_readl(addr)      (*(volatile unsigned int *)(addr))
+#define __raw_readb(addr)                                              \
+       (*(volatile unsigned char *) __swizzle_addr_b((unsigned long)(addr)))
+#define __raw_readw(addr)                                              \
+       (*(volatile unsigned short *) __swizzle_addr_w((unsigned long)(addr)))
+#define __raw_readl(addr)                                              \
+       (*(volatile unsigned int *) __swizzle_addr_l((unsigned long)(addr)))
 #ifdef CONFIG_MIPS32
 #define ____raw_readq(addr)                                            \
 ({                                                                     \
@@ -259,7 +263,7 @@ static inline void iounmap(void *addr)
                "       sll     %L0, %L0, 0                     \n"     \
                "       .set    mips0                           \n"     \
                : "=r" (__res)                                          \
-               : "r" (addr));                                          \
+               : "r" (__swizzle_addr_q((unsigned long)(addr))));       \
        __res;                                                          \
 })
 #define __raw_readq(addr)                                              \
@@ -274,7 +278,8 @@ static inline void iounmap(void *addr)
 })
 #endif
 #ifdef CONFIG_MIPS64
-#define ____raw_readq(addr)    (*(volatile unsigned long *)(addr))
+#define ____raw_readq(addr)                                            \
+       (*(volatile unsigned long *)__swizzle_addr_q((unsigned long)(addr)))
 #define __raw_readq(addr)      ____raw_readq(addr)
 #endif
 
@@ -287,12 +292,24 @@ static inline void iounmap(void *addr)
 #define readl_relaxed(addr)    readl(addr)
 #define readq_relaxed(addr)    readq(addr)
 
-#define __raw_writeb(b,addr)   ((*(volatile unsigned char *)(addr)) = (b))
-#define __raw_writew(w,addr)   ((*(volatile unsigned short *)(addr)) = (w))
-#define __raw_writel(l,addr)   ((*(volatile unsigned int *)(addr)) = (l))
+#define __raw_writeb(b,addr)                                           \
+do {                                                                   \
+       ((*(volatile unsigned char *)__swizzle_addr_b((unsigned long)(addr))) = (b));   \
+} while (0)
+
+#define __raw_writew(w,addr)                                           \
+do {                                                                   \
+       ((*(volatile unsigned short *)__swizzle_addr_w((unsigned long)(addr))) = (w));  \
+} while (0)
+
+#define __raw_writel(l,addr)                                           \
+do {                                                                   \
+       ((*(volatile unsigned int *)__swizzle_addr_l((unsigned long)(addr))) = (l));    \
+} while (0)
+
 #ifdef CONFIG_MIPS32
-#define ____raw_writeq(val,addr)                                               \
-({                                                                     \
+#define ____raw_writeq(val,addr)                                       \
+do {                                                                   \
        u64 __tmp;                                                      \
                                                                        \
        __asm__ __volatile__ (                                          \
@@ -304,19 +321,25 @@ static inline void iounmap(void *addr)
                "       sd      %L0, (%2)                       \n"     \
                "       .set    mips0                           \n"     \
                : "=r" (__tmp)                                          \
-               : "0" ((unsigned long long)val), "r" (addr));           \
-})
+               : "0" ((unsigned long long)val),                        \
+                 "r" (__swizzle_addr_q((unsigned long)(addr))));       \
+} while (0)
+
 #define __raw_writeq(val,addr)                                         \
-({                                                                     \
+do {                                                                   \
        unsigned long __flags;                                          \
                                                                        \
        local_irq_save(__flags);                                        \
        ____raw_writeq(val, addr);                                      \
        local_irq_restore(__flags);                                     \
-})
+} while (0)
 #endif
 #ifdef CONFIG_MIPS64
-#define ____raw_writeq(q,addr) ((*(volatile unsigned long *)(addr)) = (q))
+#define ____raw_writeq(q,addr)                                         \
+do {                                                                   \
+       *(volatile unsigned long *)__swizzle_addr_q((unsigned long)(addr)) = (q);       \
+} while (0)
+
 #define __raw_writeq(q,addr)   ____raw_writeq(q, addr)
 #endif
 
@@ -325,6 +348,9 @@ static inline void iounmap(void *addr)
 #define writel(l,addr)         __raw_writel(__ioswab32(l),(addr))
 #define writeq(q,addr)         __raw_writeq(__ioswab64(q),(addr))
 
+/* Depends on MIPS II instruction set */
+#define mmiowb() asm volatile ("sync" ::: "memory")
+
 #define memset_io(a,b,c)       memset((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)     memcpy((void *)(a),(b),(c))
@@ -384,20 +410,6 @@ out:
        return retval;
 }
 
-/*
- *     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.
- */
-#define isa_check_signature(io, s, l)  check_signature(i,s,l)
-
 static inline void __outb(unsigned char val, unsigned long port)
 {
        port = __swizzle_addr_b(port);
index 8caae23..556843a 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Definitions for the SGI O2 Crime chip.
+ * Definitions for the SGI CRIME (CPU, Rendering, Interconnect and Memory
+ * Engine)
  *
  * 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
 #ifndef __ASM_CRIME_H__
 #define __ASM_CRIME_H__
 
-#include <asm/addrspace.h>
-#include <asm/io.h>
-
 /*
  * Address map
  */
 #define CRIME_BASE     0x14000000      /* physical */
 
-extern void *sgi_crime;
-
-static inline uint64_t crime_read(unsigned long offset)
-{
-        return readq(sgi_crime + offset);
-}
-static inline void crime_write(uint64_t val, unsigned long offset)
-{
-       writeq(val, sgi_crime + offset);
-}
-
 #undef BIT
-#define BIT(x) (1UL << (x))
-
-/* All CRIME registers are 64 bits */
-#define CRIME_ID               0x000
-
-#define CRIME_ID_MASK          0xff
-#define CRIME_ID_IDBITS                0xf0
-#define CRIME_ID_IDVALUE       0xa0
-#define CRIME_ID_REV           0x0f
-
-#define CRIME_REV_PETTY                0x00
-#define CRIME_REV_11           0x11
-#define CRIME_REV_13           0x13
-#define CRIME_REV_14           0x14
-
-#define CRIME_CONTROL          0x008
-#define CRIME_CONTROL_MASK     0x3fff
-
-/* CRIME_CONTROL register bits */
+#define BIT(x) (1UL << (x))
+
+struct sgi_crime {
+       volatile unsigned long id;
+#define CRIME_ID_MASK                  0xff
+#define CRIME_ID_IDBITS                        0xf0
+#define CRIME_ID_IDVALUE               0xa0
+#define CRIME_ID_REV                   0x0f
+#define CRIME_REV_PETTY                        0x00
+#define CRIME_REV_11                   0x11
+#define CRIME_REV_13                   0x13
+#define CRIME_REV_14                   0x14
+
+       volatile unsigned long control;
+#define CRIME_CONTROL_MASK             0x3fff
 #define CRIME_CONTROL_TRITON_SYSADC    0x2000
 #define CRIME_CONTROL_CRIME_SYSADC     0x1000
 #define CRIME_CONTROL_HARD_RESET       0x0800
 #define CRIME_CONTROL_SOFT_RESET       0x0400
 #define CRIME_CONTROL_DOG_ENA          0x0200
 #define CRIME_CONTROL_ENDIANESS                0x0100
-
 #define CRIME_CONTROL_ENDIAN_BIG       0x0100
 #define CRIME_CONTROL_ENDIAN_LITTLE    0x0000
-
 #define CRIME_CONTROL_CQUEUE_HWM       0x000f
 #define CRIME_CONTROL_CQUEUE_SHFT      0
 #define CRIME_CONTROL_WBUF_HWM         0x00f0
 #define CRIME_CONTROL_WBUF_SHFT                8
 
-#define CRIME_INT_STAT                 0x010
-#define CRIME_INT_MASK                 0x018
-#define CRIME_SOFT_INT                 0x020
-#define CRIME_HARD_INT                 0x028
-
-/* Bits in CRIME_INT_XXX and CRIME_HARD_INT */
-#define MACE_VID_IN1_INT               BIT (0)
-#define MACE_VID_IN2_INT               BIT (1)
-#define MACE_VID_OUT_INT               BIT (2)
-#define MACE_ETHERNET_INT              BIT (3)
-#define MACE_SUPERIO_INT               BIT (4)
-#define MACE_MISC_INT                  BIT (5)
-#define MACE_AUDIO_INT                 BIT (6)
-#define MACE_PCI_BRIDGE_INT            BIT (7)
-#define MACEPCI_SCSI0_INT              BIT (8)
-#define MACEPCI_SCSI1_INT              BIT (9)
-#define MACEPCI_SLOT0_INT              BIT (10)
-#define MACEPCI_SLOT1_INT              BIT (11)
-#define MACEPCI_SLOT2_INT              BIT (12)
-#define MACEPCI_SHARED0_INT            BIT (13)
-#define MACEPCI_SHARED1_INT            BIT (14)
-#define MACEPCI_SHARED2_INT            BIT (15)
-#define CRIME_GBE0_INT                 BIT (16)
-#define CRIME_GBE1_INT                 BIT (17)
-#define CRIME_GBE2_INT                 BIT (18)
-#define CRIME_GBE3_INT                 BIT (19)
-#define CRIME_CPUERR_INT               BIT (20)
-#define CRIME_MEMERR_INT               BIT (21)
-#define CRIME_RE_EMPTY_E_INT           BIT (22)
-#define CRIME_RE_FULL_E_INT            BIT (23)
-#define CRIME_RE_IDLE_E_INT            BIT (24)
-#define CRIME_RE_EMPTY_L_INT           BIT (25)
-#define CRIME_RE_FULL_L_INT            BIT (26)
-#define CRIME_RE_IDLE_L_INT                    BIT (27)
-#define CRIME_SOFT0_INT                        BIT (28)
-#define CRIME_SOFT1_INT                        BIT (29)
-#define CRIME_SOFT2_INT                        BIT (30)
+       volatile unsigned long istat;
+       volatile unsigned long imask;
+       volatile unsigned long soft_int;
+       volatile unsigned long hard_int;
+#define MACE_VID_IN1_INT               BIT(0)
+#define MACE_VID_IN2_INT               BIT(1)
+#define MACE_VID_OUT_INT               BIT(2)
+#define MACE_ETHERNET_INT              BIT(3)
+#define MACE_SUPERIO_INT               BIT(4)
+#define MACE_MISC_INT                  BIT(5)
+#define MACE_AUDIO_INT                 BIT(6)
+#define MACE_PCI_BRIDGE_INT            BIT(7)
+#define MACEPCI_SCSI0_INT              BIT(8)
+#define MACEPCI_SCSI1_INT              BIT(9)
+#define MACEPCI_SLOT0_INT              BIT(10)
+#define MACEPCI_SLOT1_INT              BIT(11)
+#define MACEPCI_SLOT2_INT              BIT(12)
+#define MACEPCI_SHARED0_INT            BIT(13)
+#define MACEPCI_SHARED1_INT            BIT(14)
+#define MACEPCI_SHARED2_INT            BIT(15)
+#define CRIME_GBE0_INT                 BIT(16)
+#define CRIME_GBE1_INT                 BIT(17)
+#define CRIME_GBE2_INT                 BIT(18)
+#define CRIME_GBE3_INT                 BIT(19)
+#define CRIME_CPUERR_INT               BIT(20)
+#define CRIME_MEMERR_INT               BIT(21)
+#define CRIME_RE_EMPTY_E_INT           BIT(22)
+#define CRIME_RE_FULL_E_INT            BIT(23)
+#define CRIME_RE_IDLE_E_INT            BIT(24)
+#define CRIME_RE_EMPTY_L_INT           BIT(25)
+#define CRIME_RE_FULL_L_INT            BIT(26)
+#define CRIME_RE_IDLE_L_INT                    BIT(27)
+#define CRIME_SOFT0_INT                        BIT(28)
+#define CRIME_SOFT1_INT                        BIT(29)
+#define CRIME_SOFT2_INT                        BIT(30)
 #define CRIME_SYSCORERR_INT            CRIME_SOFT2_INT
-#define CRIME_VICE_INT                 BIT (31)
-
+#define CRIME_VICE_INT                 BIT(31)
 /* Masks for deciding who handles the interrupt */
 #define CRIME_MACE_INT_MASK            0x8f
 #define CRIME_MACEISA_INT_MASK         0x70
 #define CRIME_MACEPCI_INT_MASK         0xff00
 #define CRIME_CRIME_INT_MASK           0xffff0000
 
-#define CRIME_DOG                      0x030
-#define CRIME_DOG_MASK                 0x001fffff
-
-/* CRIME_DOG register bits */
+       volatile unsigned long watchdog;
 #define CRIME_DOG_POWER_ON_RESET       0x00010000
 #define CRIME_DOG_WARM_RESET           0x00080000
 #define CRIME_DOG_TIMEOUT              (CRIME_DOG_POWER_ON_RESET|CRIME_DOG_WARM_RESET)
 #define CRIME_DOG_VALUE                        0x00007fff
 
-#define CRIME_TIMER                    0x038
-#define CRIME_TIMER_MASK               0x0000ffffffffffff
-
+       volatile unsigned long timer;
 #define CRIME_MASTER_FREQ              66666500        /* Crime upcounter frequency */
 #define CRIME_NS_PER_TICK              15              /* for delay_calibrate */
 
-#define CRIME_CPU_ERROR_ADDR           0x040
+       volatile unsigned long cpu_error_addr;
 #define CRIME_CPU_ERROR_ADDR_MASK      0x3ffffffff
 
-#define CRIME_CPU_ERROR_STAT           0x048
-/* REV_PETTY only! */
-#define CRIME_CPU_ERROR_ENA            0x050
-
-/*
- * bit definitions for CRIME/VICE error status and enable registers
- */
-#define CRIME_CPU_ERROR_MASK           0x7     /* cpu error stat is 3 bits */
-#define CRIME_CPU_ERROR_CPU_ILL_ADDR   0x4
-#define CRIME_CPU_ERROR_VICE_WRT_PRTY  0x2
-#define CRIME_CPU_ERROR_CPU_WRT_PRTY   0x1
+       volatile unsigned long cpu_error_stat;
+#define CRIME_CPU_ERROR_MASK           0x7             /* cpu error stat is 3 bits */
+#define CRIME_CPU_ERROR_CPU_ILL_ADDR   0x4
+#define CRIME_CPU_ERROR_VICE_WRT_PRTY  0x2
+#define CRIME_CPU_ERROR_CPU_WRT_PRTY   0x1
 
-/*
- * these are the definitions for the error status/enable  register in
- * petty crime.  Note that the enable register does not exist in crime
- * rev 1 and above.
- */
-#define CRIME_CPU_ERROR_MASK_REV0              0x3ff   /* cpu error stat is 9 bits */
-#define CRIME_CPU_ERROR_CPU_INV_ADDR_RD                0x200
-#define CRIME_CPU_ERROR_VICE_II                        0x100
-#define CRIME_CPU_ERROR_VICE_SYSAD             0x80
-#define CRIME_CPU_ERROR_VICE_SYSCMD            0x40
-#define CRIME_CPU_ERROR_VICE_INV_ADDR          0x20
-#define CRIME_CPU_ERROR_CPU_II                 0x10
-#define CRIME_CPU_ERROR_CPU_SYSAD              0x8
-#define CRIME_CPU_ERROR_CPU_SYSCMD             0x4
-#define CRIME_CPU_ERROR_CPU_INV_ADDR_WR                0x2
-#define CRIME_CPU_ERROR_CPU_INV_REG_ADDR       0x1
-
-#define CRIME_VICE_ERROR_ADDR          0x058
-#define CRIME_VICE_ERROR_ADDR_MASK     0x3fffffff
-
-#define CRIME_MEM_CONTROL              0x200
-#define CRIME_MEM_CONTROL_MASK         0x3     /* 25 cent register */
-#define CRIME_MEM_CONTROL_ECC_ENA      0x1
-#define CRIME_MEM_CONTROL_USE_ECC_REPL 0x2
+       unsigned long _pad0[54];
 
-/*
- * macros for CRIME memory bank control registers.
- */
-#define CRIME_MEM_BANK_CONTROL(__bank)         (0x208 + ((__bank) << 3))
-#define CRIME_MEM_BANK_CONTROL_MASK            0x11f /* 9 bits 7:5 reserved */
+       volatile unsigned long mc_ctrl;
+       volatile unsigned long bank_ctrl[8];
+#define CRIME_MEM_BANK_CONTROL_MASK            0x11f   /* 9 bits 7:5 reserved */
 #define CRIME_MEM_BANK_CONTROL_ADDR            0x01f
 #define CRIME_MEM_BANK_CONTROL_SDRAM_SIZE      0x100
 #define CRIME_MAXBANKS                         8
 
-#define CRIME_MEM_REFRESH_COUNTER      0x248
-#define CRIME_MEM_REFRESH_COUNTER_MASK 0x7ff   
+       volatile unsigned long mem_ref_counter;
+#define CRIME_MEM_REF_COUNTER_MASK     0x3ff           /* 10bit */
 
-/*
- * CRIME Memory error status register bit definitions
- */
-#define CRIME_MEM_ERROR_STAT           0x250
-#define CRIME_MEM_ERROR_STAT_MASK       0x0ff7ffff    /* 28-bit register */
+       volatile unsigned long mem_error_stat;
+#define CRIME_MEM_ERROR_STAT_MASK       0x0ff7ffff     /* 28-bit register */
 #define CRIME_MEM_ERROR_MACE_ID                0x0000007f
 #define CRIME_MEM_ERROR_MACE_ACCESS    0x00000080
 #define CRIME_MEM_ERROR_RE_ID          0x00007f00
@@ -200,18 +139,21 @@ static inline void crime_write(uint64_t val, unsigned long offset)
 #define CRIME_MEM_ERROR_INV            0x0e000000
 #define CRIME_MEM_ERROR_INV_MEM_ADDR_RD        0x02000000
 #define CRIME_MEM_ERROR_INV_MEM_ADDR_WR        0x04000000
-#define CRIME_MEM_ERROR_INV_MEM_ADDR_RMW       0x08000000
+#define CRIME_MEM_ERROR_INV_MEM_ADDR_RMW 0x08000000
 
-#define CRIME_MEM_ERROR_ADDR           0x258
+       volatile unsigned long mem_error_addr;
 #define CRIME_MEM_ERROR_ADDR_MASK      0x3fffffff
 
-#define CRIME_MEM_ERROR_ECC_SYN                0x260
+       volatile unsigned long mem_ecc_syn;
 #define CRIME_MEM_ERROR_ECC_SYN_MASK   0xffffffff
 
-#define CRIME_MEM_ERROR_ECC_CHK                0x268
-#define CRIME_MEM_ERROR_ECC_CHK_MASK    0xffffffff
+       volatile unsigned long mem_ecc_chk;
+#define CRIME_MEM_ERROR_ECC_CHK_MASK   0xffffffff
 
-#define CRIME_MEM_ERROR_ECC_REPL       0x270
+       volatile unsigned long mem_ecc_repl;
 #define CRIME_MEM_ERROR_ECC_REPL_MASK  0xffffffff
+};
+
+extern struct sgi_crime *crime;
 
 #endif /* __ASM_CRIME_H__ */
index 255e9b2..2b7b0fd 100644 (file)
 #ifndef __ASM_MACE_H__
 #define __ASM_MACE_H__
 
-#include <linux/config.h>
-#include <asm/io.h>
-
 /*
  * Address map
  */
 #define MACE_BASE      0x1f000000      /* physical */
 
 #undef BIT
-#define BIT(x) (1ULL << (x))
-
-#ifdef CONFIG_MIPS32
-typedef struct {
-       volatile unsigned long long reg;
-} mace64_t;
-
-typedef struct {
-       unsigned long pad;
-       volatile unsigned long reg;
-} mace32_t;
-#endif
-#ifdef CONFIG_MIPS64
-typedef struct {
-       volatile unsigned long reg;
-} mace64_t;
-
-typedef struct {
-       volatile unsigned long reg;
-} mace32_t;
-#endif
-
-#define mace_read(r)   \
-       (sizeof(r.reg) == 4 ? readl(&r.reg) : readq(&r.reg))
-#define mace_write(v,r)        \
-       (sizeof(r.reg) == 4 ? writel(v,&r.reg) : writeq(v,&r.reg))
+#define BIT(x) (1UL << (x))
 
 /*
  * PCI interface
@@ -119,48 +91,43 @@ struct mace_pci {
  * Video interface
  */
 struct mace_video {
-       mace32_t xxx;   /* later... */
+       unsigned long xxx;      /* later... */
 };
 
 /* 
  * Ethernet interface
  */
 struct mace_ethernet {
-       mace32_t mac_ctrl;
-       mace32_t int_stat;
-       mace32_t dma_ctrl;
-       mace32_t timer;
-       mace32_t tx_int_al;
-       mace32_t rx_int_al;
-       mace32_t tx_info;
-       mace32_t tx_info_al;
-       mace32_t rx_buff;
-       mace32_t rx_buff_al1;
-       mace32_t rx_buff_al2;
-       mace64_t diag;
-       mace32_t phy_data;
-       mace32_t phy_regs;
-       mace32_t phy_trans_go;
-       mace32_t backoff_seed;
+       volatile unsigned long mac_ctrl;
+       volatile unsigned long int_stat;
+       volatile unsigned long dma_ctrl;
+       volatile unsigned long timer;
+       volatile unsigned long tx_int_al;
+       volatile unsigned long rx_int_al;
+       volatile unsigned long tx_info;
+       volatile unsigned long tx_info_al;
+       volatile unsigned long rx_buff;
+       volatile unsigned long rx_buff_al1;
+       volatile unsigned long rx_buff_al2;
+       volatile unsigned long diag;
+       volatile unsigned long phy_data;
+       volatile unsigned long phy_regs;
+       volatile unsigned long phy_trans_go;
+       volatile unsigned long backoff_seed;
        /*===================================*/
-       mace64_t imq_reserved[4];
-       mace64_t mac_addr;
-       mace64_t mac_addr2;
-       mace64_t mcast_filter;
-       mace32_t tx_ring_base;
+       volatile unsigned long imq_reserved[4];
+       volatile unsigned long mac_addr;
+       volatile unsigned long mac_addr2;
+       volatile unsigned long mcast_filter;
+       volatile unsigned long tx_ring_base;
        /* Following are read-only registers for debugging */
-       mace64_t tx_pkt1_hdr;
-       mace64_t tx_pkt1_ptr[3];
-       mace64_t tx_pkt2_hdr;
-       mace64_t tx_pkt2_ptr[3];
+       volatile unsigned long tx_pkt1_hdr;
+       volatile unsigned long tx_pkt1_ptr[3];
+       volatile unsigned long tx_pkt2_hdr;
+       volatile unsigned long tx_pkt2_ptr[3];
        /*===================================*/
-       mace32_t rx_fifo;
+       volatile unsigned long rx_fifo;
 };
-#define mace_eth_read(r)       \
-       mace_read(mace->eth.r)
-#define mace_eth_write(v,r)    \
-       mace_write(v,mace->eth.r)
-
 
 /* 
  * Peripherals
@@ -168,28 +135,24 @@ struct mace_ethernet {
 
 /* Audio registers */
 struct mace_audio {
-       mace32_t control;
-       mace32_t codec_control;         /* codec status control */
-       mace32_t codec_mask;            /* codec status input mask */
-       mace32_t codec_read;            /* codec status read data */
+       volatile unsigned long control;
+       volatile unsigned long codec_control;           /* codec status control */
+       volatile unsigned long codec_mask;              /* codec status input mask */
+       volatile unsigned long codec_read;              /* codec status read data */
        struct {
-               mace32_t control;       /* channel control */
-               mace32_t read_ptr;      /* channel read pointer */
-               mace32_t write_ptr;     /* channel write pointer */
-               mace32_t depth;         /* channel depth */
-       } channel[3];
+               volatile unsigned long control;         /* channel control */
+               volatile unsigned long read_ptr;        /* channel read pointer */
+               volatile unsigned long write_ptr;       /* channel write pointer */
+               volatile unsigned long depth;           /* channel depth */
+       } chan[3];
 };
-#define mace_perif_audio_read(r)       \
-       mace_read(mace->perif.audio.r)
-#define mace_perif_audio_write(v,r)    \
-       mace_write(v,mace->perif.audio.r)
 
 /* ISA Control and DMA registers */
 struct mace_isactrl {
-       mace32_t ringbase;
+       volatile unsigned long ringbase;
 #define MACEISA_RINGBUFFERS_SIZE       (8 * 4096)
 
-       mace32_t misc;
+       volatile unsigned long misc;
 #define MACEISA_FLASH_WE               BIT(0)  /* 1=> Enable FLASH writes */
 #define MACEISA_PWD_CLEAR              BIT(1)  /* 1=> PWD CLEAR jumper detected */
 #define MACEISA_NIC_DEASSERT           BIT(2)
@@ -198,8 +161,8 @@ struct mace_isactrl {
 #define MACEISA_LED_GREEN              BIT(5)  /* 0=> Illuminate green LED */
 #define MACEISA_DP_RAM_ENABLE          BIT(6)
 
-       mace32_t istat;
-       mace32_t imask;
+       volatile unsigned long istat;
+       volatile unsigned long imask;
 #define MACEISA_AUDIO_SW_INT           BIT(0)
 #define MACEISA_AUDIO_SC_INT           BIT(1)
 #define MACEISA_AUDIO1_DMAT_INT                BIT(2)
@@ -233,22 +196,18 @@ struct mace_isactrl {
 #define MACEISA_SERIAL2_RDMAT_INT      BIT(30)
 #define MACEISA_SERIAL2_RDMAOR_INT     BIT(31)
 
-       mace64_t _pad[0x2000/8 - 4];
+       volatile unsigned long _pad[0x2000/8 - 4];
 
-       mace64_t dp_ram[0x400];
+       volatile unsigned long dp_ram[0x400];
 };
-#define mace_perif_ctrl_read(r)                \
-       mace_read(mace->perif.ctrl.r)
-#define mace_perif_ctrl_write(v,r)     \
-       mace_write(v,mace->perif.ctrl.r)
 
 /* Keyboard & Mouse registers
  * -> drivers/input/serio/maceps2.c */
 struct mace_ps2port {
-       mace32_t tx;
-       mace32_t rx;
-       mace32_t control;
-       mace32_t status;
+       volatile unsigned long tx;
+       volatile unsigned long rx;
+       volatile unsigned long control;
+       volatile unsigned long status;
 };
 
 struct mace_ps2 {
@@ -259,20 +218,20 @@ struct mace_ps2 {
 /* I2C registers
  * -> drivers/i2c/algos/i2c-algo-sgi.c */
 struct mace_i2c {
-       mace32_t config;
+       volatile unsigned long config;
 #define MACEI2C_RESET           BIT(0)
 #define MACEI2C_FAST            BIT(1)
 #define MACEI2C_DATA_OVERRIDE   BIT(2)
 #define MACEI2C_CLOCK_OVERRIDE  BIT(3)
 #define MACEI2C_DATA_STATUS     BIT(4)
 #define MACEI2C_CLOCK_STATUS    BIT(5)
-       mace32_t control;
-       mace32_t data;
+       volatile unsigned long control;
+       volatile unsigned long data;
 };
 
 /* Timer registers */
 typedef union {
-       mace64_t ust_msc;
+       volatile unsigned long ust_msc;
        struct reg {
                volatile unsigned int ust;
                volatile unsigned int msc;
@@ -280,12 +239,12 @@ typedef union {
 } timer_reg;
 
 struct mace_timers {
-       mace32_t ust;
+       volatile unsigned long ust;
 #define MACE_UST_PERIOD_NS     960
 
-       mace32_t compare1;
-       mace32_t compare2;
-       mace32_t compare3;
+       volatile unsigned long compare1;
+       volatile unsigned long compare2;
+       volatile unsigned long compare3;
 
        timer_reg audio_in;
        timer_reg audio_out1;
@@ -326,7 +285,7 @@ struct mace_ecp1284 {       /* later... */
 
 /* Serial port */
 struct mace_serial {
-       mace64_t xxx;   /* later... */
+       volatile unsigned long xxx;     /* later... */
 };
 
 struct mace_isa {
index d9667a8..b90b11d 100644 (file)
@@ -22,14 +22,32 @@ static inline int irq_canonicalize(int irq)
 #define irq_canonicalize(irq) (irq)    /* Sane hardware, sane code ... */
 #endif
 
-extern void disable_irq(unsigned int);
-extern void disable_irq_nosync(unsigned int);
-extern void enable_irq(unsigned int);
-
 struct pt_regs;
-extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
 
-extern void init_generic_irq(void);
+#ifdef CONFIG_PREEMPT
+
+extern asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs);
+
+#else
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ *
+ * Ideally there should be away to get this into kernel/irq/handle.c to
+ * avoid the overhead of a call for just a tiny function ...
+ */
+#define do_IRQ(irq, regs)                                              \
+do {                                                                   \
+       irq_enter();                                                    \
+       __do_IRQ((irq), (regs));                                        \
+       irq_exit();                                                     \
+} while (0)
+
+#endif
+
+extern void arch_init_irq(void);
 
 struct irqaction;
 int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
index 4e62ee6..81cbf00 100644 (file)
@@ -107,6 +107,8 @@ typedef struct {
        unsigned char command;
 } jazz_keyboard_hardware;
 
+#define jazz_kh ((keyboard_hardware *) JAZZ_KEYBOARD_ADDRESS)
+
 typedef struct {
        unsigned char pad0[3];
        unsigned char data;
index 8799f92..64f3b1a 100644 (file)
@@ -29,7 +29,7 @@
 #define RTC_EXTENT     16
 #define RTC_IRQ                ATLASINT_RTC
 
-#if CONFIG_CPU_LITTLE_ENDIAN
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
 #define ATLAS_RTC_PORT(x) (RTC_PORT(x) + 0)
 #else
 #define ATLAS_RTC_PORT(x) (RTC_PORT(x) + 3)
index d476013..682a585 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
-#include <linux/kernel.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
 #include <linux/mm.h>
index ba82007..4a98d83 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 2004 Ralf Baechle
  */
 #ifndef __ASM_MACH_GENERIC_MANGLE_PORT_H
 #define __ASM_MACH_GENERIC_MANGLE_PORT_H
@@ -11,5 +11,6 @@
 #define __swizzle_addr_b(port) (port)
 #define __swizzle_addr_w(port) (port)
 #define __swizzle_addr_l(port) (port)
+#define __swizzle_addr_q(port) (port)
 
 #endif /* __ASM_MACH_GENERIC_MANGLE_PORT_H */
index 4b565cf..63c0a81 100644 (file)
@@ -7,8 +7,8 @@
  * Copyright (C) 2000, 2002  Maciej W. Rozycki
  * Copyright (C) 1990, 1999, 2000 Silicon Graphics, Inc.
  */
-#ifndef _ASM_MACH_SPACES_H
-#define _ASM_MACH_SPACES_H
+#ifndef _ASM_MACH_GENERIC_SPACES_H
+#define _ASM_MACH_GENERIC_SPACES_H
 
 #include <linux/config.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 */
index 661995e..f76c448 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 2004 Ralf Baechle
  */
 #ifndef __ASM_MACH_IP27_MANGLE_PORT_H
 #define __ASM_MACH_IP27_MANGLE_PORT_H
@@ -11,5 +11,6 @@
 #define __swizzle_addr_b(port) (port)
 #define __swizzle_addr_w(port) ((port) ^ 2)
 #define __swizzle_addr_l(port) (port)
+#define __swizzle_addr_q(port) (port)
 
 #endif /* __ASM_MACH_IP27_MANGLE_PORT_H */
index 4d95609..d3f5663 100644 (file)
@@ -3,7 +3,34 @@
 
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
+#include <asm/sn/hub.h>
 
 #define pa_to_nid(addr)                NASID_TO_COMPACT_NODEID(NASID_GET(addr))
 
+#define LEVELS_PER_SLICE        128
+
+struct slice_data {
+       unsigned long irq_alloc_mask[2];
+       unsigned long irq_enable_mask[2];
+       int level_to_irq[LEVELS_PER_SLICE];
+};
+
+struct hub_data {
+       kern_vars_t     kern_vars;
+       DECLARE_BITMAP(h_bigwin_used, HUB_NUM_BIG_WINDOW);
+       cpumask_t       h_cpus;
+       unsigned long slice_map;
+       struct slice_data slice[2];
+};
+
+struct node_data {
+       struct pglist_data pglist;
+       struct hub_data hub;
+};
+
+extern struct node_data *__node_data[];
+
+#define NODE_DATA(n)           (&__node_data[(n)]->pglist)
+#define hub_data(n)            (&__node_data[(n)]->hub)
+
 #endif /* _ASM_MACH_MMZONE_H */
index e0cf74d..e3b3fe3 100644 (file)
@@ -7,8 +7,8 @@
  * Copyright (C) 2000, 2002  Maciej W. Rozycki
  * Copyright (C) 1990, 1999 by Silicon Graphics, Inc.
  */
-#ifndef _ASM_MACH_SPACES_H
-#define _ASM_MACH_SPACES_H
+#ifndef _ASM_MACH_IP27_SPACES_H
+#define _ASM_MACH_IP27_SPACES_H
 
 /*
  * IP27 uses the R10000's uncached attribute feature.  Attribute 3 selects
@@ -31,4 +31,4 @@
 
 #define HIGHMEM_START          (~0UL)
 
-#endif /* _ASM_MACH_SPACES_H */
+#endif /* _ASM_MACH_IP27_SPACES_H */
index 0e93126..a70a812 100644 (file)
@@ -1,18 +1,38 @@
 #ifndef _ASM_MACH_TOPOLOGY_H
 #define _ASM_MACH_TOPOLOGY_H   1
 
+#include <asm/sn/arch.h>
 #include <asm/sn/hub.h>
+#include <asm/mmzone.h>
 
 #define cpu_to_node(cpu)       (cpu_data[(cpu)].p_nodeid)
 #define parent_node(node)      (node)
-#define node_to_cpumask(node)  (HUB_DATA(node)->h_cpus)
+#define node_to_cpumask(node)  (hub_data(node)->h_cpus)
 #define node_to_first_cpu(node)        (first_cpu(node_to_cpumask(node)))
 #define pcibus_to_cpumask(bus) (cpu_online_map)
 
-extern int node_distance(nasid_t nasid_a, nasid_t nasid_b);
-#define node_distance(from, to)        node_distance(from, to)
+extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
 
-/* Cross-node load balancing interval. */
-#define NODE_BALANCE_RATE      10
+#define node_distance(from, to)        (__node_distances[(from)][(to)])
+
+/* sched_domains SD_NODE_INIT for SGI IP27 machines */
+#define SD_NODE_INIT (struct sched_domain) {           \
+       .span                   = CPU_MASK_NONE,        \
+       .parent                 = NULL,                 \
+       .groups                 = NULL,                 \
+       .min_interval           = 8,                    \
+       .max_interval           = 32,                   \
+       .busy_factor            = 32,                   \
+       .imbalance_pct          = 125,                  \
+       .cache_hot_time         = (10*1000),            \
+       .cache_nice_tries       = 1,                    \
+       .per_cpu_gain           = 100,                  \
+       .flags                  = SD_LOAD_BALANCE       \
+                               | SD_BALANCE_EXEC       \
+                               | SD_WAKE_BALANCE,      \
+       .last_balance           = jiffies,              \
+       .balance_interval       = 1,                    \
+       .nr_balance_failed      = 0,                    \
+}
 
 #endif /* _ASM_MACH_TOPOLOGY_H */
index 6842af4..6e25b52 100644 (file)
@@ -4,6 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2003 Ladislav Michl
+ * Copyright (C) 2004 Ralf Baechle
  */
 #ifndef __ASM_MACH_IP32_MANGLE_PORT_H
 #define __ASM_MACH_IP32_MANGLE_PORT_H
@@ -11,5 +12,6 @@
 #define __swizzle_addr_b(port) ((port) ^ 3)
 #define __swizzle_addr_w(port) ((port) ^ 2)
 #define __swizzle_addr_l(port) (port)
+#define __swizzle_addr_q(port) (port)
 
 #endif /* __ASM_MACH_IP32_MANGLE_PORT_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 */
index 2dce66f..d2018eb 100644 (file)
 #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-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 */
index 1de5c32..ae12c1c 100644 (file)
 #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_YOSEMITE_CPU_FEATURE_OVERRIDES_H */
index 2e3bc67..9225b33 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/pci.h>
 
 #include <asm/byteorder.h>
-#include <asm/pci_channel.h>
 
 extern unsigned long marvell_base;
 
index 27ad26c..29ee13b 100644 (file)
@@ -8,9 +8,6 @@
 #include <asm/page.h>
 #include <mmzone.h>
 
-extern struct pglist_data *node_data[];
-
-#define NODE_DATA(n)           (node_data[(n)])
 #define kvaddr_to_nid(kvaddr)  pa_to_nid(__pa(kvaddr))
 #define pfn_to_nid(pfn)                pa_to_nid((pfn) << PAGE_SHIFT)
 
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 */
+
index fceef69..4f00c16 100644 (file)
@@ -2,6 +2,6 @@
 #define _ASM_MAX_NUMNODES_H
 
 /* Max 128 Nodes */
-#define NODES_SHIFT    7
+#define NODES_SHIFT    6
 
 #endif /* _ASM_MAX_NUMNODES_H */
index c043f64..b4ee995 100644 (file)
@@ -13,7 +13,7 @@
 #define _ASM_PCI_BRIDGE_H
 
 #include <linux/types.h>
-#include <asm/pci_channel.h>
+#include <linux/pci.h>
 #include <asm/xtalk/xwidget.h>         /* generic widget header */
 
 /* I/O page size */
@@ -830,7 +830,6 @@ typedef union ate_u {
 
 #define BRIDGE_INTERNAL_ATES   128
 
-
 struct bridge_controller {
        struct pci_controller   pc;
        struct resource         mem;
@@ -840,9 +839,13 @@ struct bridge_controller {
        unsigned int            widget_id;
        unsigned int            irq_cpu;
        dma64_addr_t            baddr;
+       unsigned int            pci_int[8];
 };
 
 #define BRIDGE_CONTROLLER(bus) \
        ((struct bridge_controller *)((bus)->sysdata))
 
+extern void register_bridge_irq(unsigned int irq);
+extern int request_bridge_irq(struct bridge_controller *bc);
+
 #endif /* _ASM_PCI_BRIDGE_H */
index 9ec0982..c2e8a00 100644 (file)
@@ -28,8 +28,8 @@ typedef unsigned int  __kernel_nlink_t;
 typedef long           __kernel_off_t;
 typedef int            __kernel_pid_t;
 typedef int            __kernel_ipc_pid_t;
-typedef int            __kernel_uid_t;
-typedef int            __kernel_gid_t;
+typedef unsigned int   __kernel_uid_t;
+typedef unsigned int   __kernel_gid_t;
 #if (_MIPS_SZLONG == 32)
 typedef unsigned int   __kernel_size_t;
 typedef int            __kernel_ssize_t;
@@ -50,8 +50,8 @@ typedef char *                __kernel_caddr_t;
 
 typedef unsigned short __kernel_uid16_t;
 typedef unsigned short __kernel_gid16_t;
-typedef int            __kernel_uid32_t;
-typedef int            __kernel_gid32_t;
+typedef unsigned int   __kernel_uid32_t;
+typedef unsigned int   __kernel_gid32_t;
 typedef __kernel_uid_t __kernel_old_uid_t;
 typedef __kernel_gid_t __kernel_old_gid_t;
 typedef unsigned int   __kernel_old_dev_t;
index 8a12fb6..649f397 100644 (file)
@@ -26,7 +26,7 @@
  *  - We need a properly sign extended address for 64-bit code.  To get away
  *    without ifdefs we let the compiler do it by a type cast.
  */
-#define INDEX_BASE     ((int) KSEG0)
+#define INDEX_BASE     CKSEG0
 
 #define cache_op(op,addr)                                              \
        __asm__ __volatile__(                                           \
index 3e16b4d..169187f 100644 (file)
@@ -120,7 +120,7 @@ extern u8 sgi_ioc_reset, sgi_ioc_write;
 struct sgioc_regs {
        struct pi1_regs pport;
        u32 _unused0[2];
-       struct sgioc_uart_regs serport;
+       struct sgioc_uart_regs uart;
        struct sgioc_keyb_regs kbdmouse;
        u8 _gcsel[3];
        volatile u8 gcsel;
index d63ef67..5945033 100644 (file)
@@ -371,7 +371,7 @@ struct linux_smonblock {
 
 #define __arc_clobbers                                                 \
        "$2","$3" /* ... */, "$8","$9","$10","$11",                     \
-       "$12","$13","$14","$15","$16","$24","25","$31"
+       "$12","$13","$14","$15","$16","$24","$25","$31"
 
 #define ARC_CALL0(dest)                                                        \
 ({     long __res;                                                     \
@@ -464,7 +464,7 @@ struct linux_smonblock {
        long __vec = (long) romvec->dest;                               \
        __asm__ __volatile__(                                           \
        "dsubu\t$29, 32\n\t"                                            \
-       "sw\t%6, 16($29)\n\t"                                           \
+       "sw\t%7, 16($29)\n\t"                                           \
        "jalr\t%1\n\t"                                                  \
        "daddu\t$29, 32\n\t"                                            \
        "move\t%0, $2"                                                  \
index fec2169..8ddd3c9 100644 (file)
@@ -13,7 +13,7 @@
 
 #define SIGEV_HEAD_SIZE        (sizeof(long) + 2*sizeof(int))
 #define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE-SIGEV_HEAD_SIZE) / sizeof(int))
-#define SI_PAD_SIZE    ((SI_MAX_SIZE/sizeof(int)) - 4)
+#undef __ARCH_SI_TRAPNO        /* exception code needs to fill this ...  */
 
 #define HAVE_ARCH_SIGINFO_T
 
 #define HAVE_ARCH_COPY_SIGINFO
 struct siginfo;
 
-#include <asm-generic/siginfo.h>
+/*
+ * Careful to keep union _sifields from shifting ...
+ */
+#ifdef CONFIG_MIPS32
+#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
+#endif
+#ifdef CONFIG_MIPS64
+#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+#endif
 
-/* This structure matches the 32/n32 ABIs for source compatibility but
-   has Linux extensions.  */
+#include <asm-generic/siginfo.h>
 
 typedef struct siginfo {
        int si_signo;
        int si_code;
        int si_errno;
+       int __pad0[SI_MAX_SIZE / sizeof(int) - SI_PAD_SIZE - 3];
 
        union {
                int _pad[SI_PAD_SIZE];
@@ -40,131 +48,57 @@ typedef struct siginfo {
                /* kill() */
                struct {
                        pid_t _pid;             /* sender's pid */
-                       uid_t _uid;             /* sender's uid */
+                       __ARCH_SI_UID_T _uid;   /* sender's uid */
                } _kill;
 
-               /* SIGCHLD */
-               struct {
-                       pid_t _pid;             /* which child */
-                       uid_t _uid;             /* sender's uid */
-                       int _status;            /* exit code */
-                       clock_t _utime;
-                       clock_t _stime;
-               } _sigchld;
-
-               /* IRIX SIGCHLD */
-               struct {
-                       pid_t _pid;             /* which child */
-                       clock_t _utime;
-                       int _status;            /* exit code */
-                       clock_t _stime;
-               } _irix_sigchld;
-
-               /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-               struct {
-                       void *_addr; /* faulting insn/memory ref. */
-               } _sigfault;
-
-               /* SIGPOLL, SIGXFSZ (To do ...)  */
-               struct {
-#ifdef CONFIG_MIPS32
-                       int _band;      /* POLL_IN, POLL_OUT, POLL_MSG */
-#endif
-#ifdef CONFIG_MIPS64
-                       long _band;     /* POLL_IN, POLL_OUT, POLL_MSG */
-#endif
-                       int _fd;
-               } _sigpoll;
-
                /* POSIX.1b timers */
                struct {
                        timer_t _tid;           /* timer id */
                        int _overrun;           /* overrun count */
                        char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
                        sigval_t _sigval;       /* same as below */
-                       int _sys_private;       /* not to be passed to user */
+                       int _sys_private;       /* not to be passed to user */
                } _timer;
 
                /* POSIX.1b signals */
                struct {
                        pid_t _pid;             /* sender's pid */
-                       uid_t _uid;             /* sender's uid */
+                       __ARCH_SI_UID_T _uid;   /* sender's uid */
                        sigval_t _sigval;
                } _rt;
 
-       } _sifields;
-} siginfo_t;
-
-#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
-
-#include <linux/compat.h>
-
-#define SI_PAD_SIZE32   ((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef union sigval32 {
-       int sival_int;
-       s32 sival_ptr;
-} sigval_t32;
-
-typedef struct siginfo32 {
-       int si_signo;
-       int si_code;
-       int si_errno;
-
-       union {
-               int _pad[SI_PAD_SIZE32];
-
-               /* kill() */
-               struct {
-                       compat_pid_t _pid;      /* sender's pid */
-                       compat_uid_t _uid;      /* sender's uid */
-               } _kill;
-
                /* SIGCHLD */
                struct {
-                       compat_pid_t _pid;      /* which child */
-                       compat_uid_t _uid;      /* sender's uid */
-                       compat_clock_t _utime;
+                       pid_t _pid;             /* which child */
+                       __ARCH_SI_UID_T _uid;   /* sender's uid */
                        int _status;            /* exit code */
-                       compat_clock_t _stime;
+                       clock_t _utime;
+                       clock_t _stime;
                } _sigchld;
 
                /* IRIX SIGCHLD */
                struct {
-                       compat_pid_t _pid;      /* which child */
-                       compat_clock_t _utime;
+                       pid_t _pid;             /* which child */
+                       clock_t _utime;
                        int _status;            /* exit code */
-                       compat_clock_t _stime;
+                       clock_t _stime;
                } _irix_sigchld;
 
                /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
                struct {
-                       s32 _addr; /* faulting insn/memory ref. */
+                       void __user *_addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_TRAPNO
+                       int _trapno;    /* TRAP # which caused the signal */
+#endif
                } _sigfault;
 
                /* SIGPOLL, SIGXFSZ (To do ...)  */
                struct {
-                       int _band;      /* POLL_IN, POLL_OUT, POLL_MSG */
+                       __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
                        int _fd;
                } _sigpoll;
-
-               /* POSIX.1b timers */
-               struct {
-                       unsigned int _timer1;
-                       unsigned int _timer2;
-               } _timer;
-
-               /* POSIX.1b signals */
-               struct {
-                       compat_pid_t _pid;      /* sender's pid */
-                       compat_uid_t _uid;      /* sender's uid */
-                       sigval_t32 _sigval;
-               } _rt;
-
        } _sifields;
-} siginfo_t32;
-
-#endif /* defined(__KERNEL__) && defined(CONFIG_COMPAT) */
+} siginfo_t;
 
 /*
  * si_code values
index a88c337..6333169 100644 (file)
@@ -13,9 +13,6 @@
 
 #include <asm/offset.h>
 
-/* Used in declaration of save_static functions.  */
-#define static_unused static __attribute__((unused))
-
 #define __str2(x) #x
 #define __str(x) __str2(x)
 
@@ -39,6 +36,7 @@ __asm__ (                                                             \
        "sw\t$22,"__str(PT_R22)"($29)\n\t"                              \
        "sw\t$23,"__str(PT_R23)"($29)\n\t"                              \
        "sw\t$30,"__str(PT_R30)"($29)\n\t"                              \
+       "j\t_" #symbol "\n\t"                                           \
        ".end\t" #symbol "\n\t"                                         \
        ".size\t" #symbol",. - " #symbol)
 
@@ -66,6 +64,7 @@ __asm__ (                                                             \
        "sd\t$22,"__str(PT_R22)"($29)\n\t"                              \
        "sd\t$23,"__str(PT_R23)"($29)\n\t"                              \
        "sd\t$30,"__str(PT_R30)"($29)\n\t"                              \
+       "j\t_" #symbol "\n\t"                                           \
        ".end\t" #symbol "\n\t"                                         \
        ".size\t" #symbol",. - " #symbol)
 
index 89b9210..1992d92 100644 (file)
@@ -8,25 +8,6 @@
 #include <asm/sn/klkernvars.h>
 #include <asm/xtalk/xtalk.h>
 
-#define LEVELS_PER_SLICE       128
-
-struct slice_data {
-       unsigned long irq_alloc_mask[2];
-       unsigned long irq_enable_mask[2];
-       int level_to_irq[LEVELS_PER_SLICE];
-};
-
-struct hub_data {
-       kern_vars_t     kern_vars;
-       DECLARE_BITMAP  (h_bigwin_used, HUB_NUM_BIG_WINDOW);
-       cpumask_t       h_cpus;
-       unsigned long slice_map;
-       struct slice_data slice[2];
-};
-
-extern struct hub_data *hub_data[];
-#define HUB_DATA(n)            (hub_data[(n)])
-
 /* ip27-hubio.c */
 extern unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget,
                          unsigned long xtalk_addr, size_t size);
index 6765d0f..c774996 100644 (file)
 #define MAPPED_KERN_RW_TO_PHYS(x) \
                                ((unsigned long)MAPPED_ADDR_RW_TO_PHYS(x) | \
                                MAPPED_KERN_RW_PHYSBASE(get_compact_nodeid()))
-#define MAPPED_OFFSET                  16777216
 
 #else /* CONFIG_MAPPED_KERNEL */
 
 #define MAPPED_KERN_RO_TO_PHYS(x)      (x - CKSEG0)
 #define MAPPED_KERN_RW_TO_PHYS(x)      (x - CKSEG0)
-#define MAPPED_OFFSET                  0
 
 #endif /* CONFIG_MAPPED_KERNEL */
 
index 8229c6e..43d5dc9 100644 (file)
@@ -10,12 +10,10 @@ extern cnodeid_t get_compact_nodeid(void);
 extern void hub_rtc_init(cnodeid_t);
 extern void cpu_time_init(void);
 extern void per_cpu_init(void);
-extern void per_hub_init(cnodeid_t cnode);
 extern void install_cpu_nmi_handler(int slice);
 extern void install_ipi(void);
 extern void setup_replication_mask(int);
 extern void replicate_kernel_text(int);
 extern pfn_t node_getfirstfree(cnodeid_t);
-extern void mlreset(void);
 
 #endif /* __ASM_SN_SN_PRIVATE_H */
index eba99d2..020b4db 100644 (file)
@@ -68,6 +68,8 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
 
 #define SO_PEERSEC             30
 
+#ifdef __KERNEL__
+
 /** sock_type - Socket types
  *
  * Please notice that for binary compat reasons MIPS has to
@@ -93,6 +95,8 @@ enum sock_type {
 
 #define SOCK_MAX (SOCK_PACKET + 1)
 
-#define ARCH_HAS_SOCKET_TYPES
+#define ARCH_HAS_SOCKET_TYPES 1
+
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_SOCKET_H */
index ef15465..5076fec 100644 (file)
@@ -28,9 +28,9 @@ struct statfs {
        long            f_bfree;
        long            f_files;
        long            f_ffree;
+       long            f_bavail;
 
        /* Linux specials */
-       long    f_bavail;
        __kernel_fsid_t f_fsid;
        long            f_namelen;
        long            f_spare[6];
@@ -44,15 +44,16 @@ struct statfs {
 struct statfs64 {
        __u32   f_type;
        __u32   f_bsize;
+       __u32   f_frsize;       /* Fragment size - unsupported */
+       __u32   __pad;
        __u64   f_blocks;
        __u64   f_bfree;
-       __u64   f_bavail;
        __u64   f_files;
        __u64   f_ffree;
+       __u64   f_bavail;
        __kernel_fsid_t f_fsid;
        __u32   f_namelen;
-       __u32   f_frsize;
-       __u32   f_spare[5];
+       __u32   f_spare[6];
 };
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
@@ -67,26 +68,27 @@ struct statfs64 {                   /* Same as struct statfs */
        long            f_bfree;
        long            f_files;
        long            f_ffree;
+       long            f_bavail;
 
        /* Linux specials */
-       long    f_bavail;
        __kernel_fsid_t f_fsid;
        long            f_namelen;
        long            f_spare[6];
 };
 
 struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
+       __u32   f_type;
+       __u32   f_bsize;
+       __u32   f_frsize;       /* Fragment size - unsupported */
+       __u32   __pad;
+       __u64   f_blocks;
+       __u64   f_bfree;
+       __u64   f_files;
+       __u64   f_ffree;
+       __u64   f_bavail;
        __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
+       __u32   f_namelen;
+       __u32   f_spare[6];
 };
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
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
index 7116b0b..5d939db 100644 (file)
@@ -88,8 +88,8 @@
 
 
 /* TX4927 Configuration registers (64-bit registers) */
-#define TX4927_CONFIG_BASE                       0xe300
-#define TX4927_CONFIG_CCFG                       0xe300
+#define TX4927_CONFIG_BASE                       0xe000
+#define TX4927_CONFIG_CCFG                       0xe000
 #define TX4927_CONFIG_CCFG_RESERVED_42_63                BM_63_42
 #define TX4927_CONFIG_CCFG_WDRST                         BM_41_41
 #define TX4927_CONFIG_CCFG_WDREXEN                       BM_40_40
 #define TX4927_CONFIG_CCFG_ENDIAN                        BM_02_02
 #define TX4927_CONFIG_CCFG_ARMODE                        BM_01_01
 #define TX4927_CONFIG_CCFG_ACEHOLD                       BM_00_00
-#define TX4927_CONFIG_REVID                      0xe308 
+#define TX4927_CONFIG_REVID                      0xe008
 #define TX4927_CONFIG_REVID_RESERVED_32_63               BM_32_63
 #define TX4927_CONFIG_REVID_PCODE                        BM_16_31
 #define TX4927_CONFIG_REVID_MJERREV                      BM_12_15
 #define TX4927_CONFIG_REVID_MINEREV                      BM_08_11
 #define TX4927_CONFIG_REVID_MJREV                        BM_04_07
 #define TX4927_CONFIG_REVID_MINREV                       BM_00_03
-#define TX4927_CONFIG_PCFG                       0xe310 
+#define TX4927_CONFIG_PCFG                       0xe010
 #define TX4927_CONFIG_PCFG_RESERVED_57_63                BM_57_63
 #define TX4927_CONFIG_PCFG_DRVDATA                       BM_56_56
 #define TX4927_CONFIG_PCFG_DRVCB                         BM_55_55
 #define TX4927_CONFIG_PCFG_DMASEL0_SIO1                  BM_00_00
 #define TX4927_CONFIG_PCFG_DMASEL0_ACLC0                 BM_01_01
 #define TX4927_CONFIG_PCFG_DMASEL0_ACLC2                 BM_00_01
-#define TX4927_CONFIG_TOEA                       0xe318 
+#define TX4927_CONFIG_TOEA                       0xe018
 #define TX4927_CONFIG_TOEA_RESERVED_36_63                BM_36_63
 #define TX4927_CONFIG_TOEA_TOEA                          BM_00_35
-#define TX4927_CONFIG_CLKCTR                     0xe320 
+#define TX4927_CONFIG_CLKCTR                     0xe020
 #define TX4927_CONFIG_CLKCTR_RESERVED_26_63              BM_26_63
 #define TX4927_CONFIG_CLKCTR_ACLCKD                      BM_25_25
 #define TX4927_CONFIG_CLKCTR_PIOCKD                      BM_24_24
 #define TX4927_CONFIG_CLKCTR_TM2RST                      BM_02_02
 #define TX4927_CONFIG_CLKCTR_SIO0RST                     BM_01_01
 #define TX4927_CONFIG_CLKCTR_SIO1RST                     BM_00_00
-#define TX4927_CONFIG_GARBC                      0xe330 
+#define TX4927_CONFIG_GARBC                      0xe030
 #define TX4927_CONFIG_GARBC_RESERVED_10_63               BM_10_63
 #define TX4927_CONFIG_GARBC_SET_09                       BM_09_09
 #define TX4927_CONFIG_GARBC_ARBMD                        BM_08_08
 #define TX4927_CONFIG_GARBC_PRIORITY_H3_PDMAC            BM_00_00
 #define TX4927_CONFIG_GARBC_PRIORITY_H3_DMAC             BM_01_01
 #define TX4927_CONFIG_GARBC_PRIORITY_H3_BAD_VALUE        BM_00_01
-#define TX4927_CONFIG_RAMP                       0xe348 
+#define TX4927_CONFIG_RAMP                       0xe048
 #define TX4927_CONFIG_RAMP_RESERVED_20_63                BM_20_63
 #define TX4927_CONFIG_RAMP_RAMP                          BM_00_19
 #define TX4927_CONFIG_LIMIT                      0xefff
 #define TX4927_ACLC_ACINTSTS            0xf710
 #define TX4927_ACLC_ACINTMSTS           0xf714
 #define TX4927_ACLC_ACINTEN             0xf718
-#define TX4927_ACLC_ACINTDIS            0xfR71c
+#define TX4927_ACLC_ACINTDIS            0xf71c
 #define TX4927_ACLC_ACSEMAPH            0xf720
 #define TX4927_ACLC_ACGPIDAT            0xf740
 #define TX4927_ACLC_ACGPODAT            0xf744
index a6f5c06..c4a7041 100644 (file)
 #define  RM9000_CDEX_SMP_WAR           1
 #endif
 
+/*
+ * ON the R10000 upto version 2.6 (not sure about 2.7) there is a bug that
+ * may cause ll / sc and lld / scd sequences to execute non-atomically.
+ */
+#ifdef CONFIG_SGI_IP27
+#define R10000_LLSC_WAR 1
+#endif
+
 /*
  * Workarounds default to off
  */
 #ifndef RM9000_CDEX_SMP_WAR
 #define RM9000_CDEX_SMP_WAR            0
 #endif
+#ifndef R10000_LLSC_WAR
+#define R10000_LLSC_WAR                        0
+#endif
 
 #endif /* _ASM_WAR_H */
index 5ba8c5c..56b5bd8 100644 (file)
 #define LDREGX  ldd,s
 #define LDREGM ldd,mb
 #define STREGM std,ma
+#define SHRREG  shrd
 #define RP_OFFSET      16
 #define FRAME_SIZE     128
+#define CALLEE_SAVE_FRAME_SIZE 144
 #else
 #define LDREG  ldw
 #define STREG  stw
 #define STREGM stwm
 #define RP_OFFSET      20
 #define FRAME_SIZE     64
+#define CALLEE_SAVE_FRAME_SIZE 128
 #endif
 
 #ifdef CONFIG_PA20
 #define BL             b,l
+# ifdef CONFIG_PARISC64
+#  define LEVEL                2.0w
+# else
+#  define LEVEL                2.0
+# endif
 #else
 #define BL             bl
+#define LEVEL          1.1
 #endif
 
 #ifdef __ASSEMBLY__
 
 #ifdef __LP64__
        .macro  callee_save
-       std,ma    %r3,  144(%r30)
+       std,ma    %r3,  CALLEE_SAVE_FRAME_SIZE(%r30)
        mfctl     %cr27, %r3
        std       %r4,  -136(%r30)
        std       %r5,  -128(%r30)
        ldd     -128(%r30),    %r5
        ldd     -136(%r30),    %r4
        mtctl   %r3, %cr27
-       ldd,mb  -144(%r30),    %r3
+       ldd,mb  -CALLEE_SAVE_FRAME_SIZE(%r30),    %r3
        .endm
 
 #else /* ! __LP64__ */
 
        .macro  callee_save
-       stw,ma   %r3,   128(%r30)
+       stw,ma   %r3,   CALLEE_SAVE_FRAME_SIZE(%r30)
        mfctl    %cr27, %r3
        stw      %r4,   -124(%r30)
        stw      %r5,   -120(%r30)
        ldw     -120(%r30),   %r5
        ldw     -124(%r30),   %r4
        mtctl   %r3, %cr27
-       ldw,mb  -128(%r30),   %r3
+       ldw,mb  -CALLEE_SAVE_FRAME_SIZE(%r30),   %r3
        .endm
 #endif /* ! __LP64__ */
 
index 98d36ad..e72f6e2 100644 (file)
@@ -1,4 +1,12 @@
 #ifndef _PARISC_BUG_H
 #define _PARISC_BUG_H
+
+#define HAVE_ARCH_BUG
+#define BUG() do { \
+       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+       dump_stack(); \
+       panic("BUG!"); \
+} while (0)
+
 #include <asm-generic/bug.h>
 #endif
index 3b0fbce..a10f109 100644 (file)
 #define        EREMOTEIO       181     /* Remote I/O error */
 #define        ENOMEDIUM       182     /* No medium found */
 #define        EMEDIUMTYPE     183     /* Wrong medium type */
+#define        ENOKEY          184     /* Required key not available */
+#define        EKEYEXPIRED     185     /* Key has expired */
+#define        EKEYREVOKED     186     /* Key has been revoked */
+#define        EKEYREJECTED    187     /* Key was rejected by service */
 
 /* We now return you to your regularly scheduled HPUX. */
 
index 7ebdebb..39f4698 100644 (file)
@@ -28,29 +28,8 @@ typedef struct {
 
 #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-31 are the hardirq count (max # of hardirqs: 65536)
- *
- * - (bit 63 is the PREEMPT_ACTIVE flag---not currently implemented.)
- *
- * PREEMPT_MASK: 0x000000ff
- * SOFTIRQ_MASK: 0x0000ff00
- * HARDIRQ_MASK: 0xffff0000
- */
-
-#define PREEMPT_BITS   8
-#define SOFTIRQ_BITS   8
 #define HARDIRQ_BITS   16
 
-#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:
index fe536cf..d9433d5 100644 (file)
@@ -177,6 +177,8 @@ extern __inline__ void ___raw_writeq(unsigned long long val, unsigned long addr)
 #define readl_relaxed(addr) readl(addr)
 #define readq_relaxed(addr) readq(addr)
 
+#define mmiowb()
+
 extern void __memcpy_fromio(unsigned long dest, unsigned long src, int count);
 extern void __memcpy_toio(unsigned long dest, unsigned long src, int count);
 extern void __memset_io(unsigned long dest, char fill, int count);
index ba34a4e..fe7c704 100644 (file)
@@ -4,6 +4,8 @@
 #include <linux/config.h>
 #include <asm/scatterlist.h>
 
+
+
 /*
 ** HP PCI platforms generally support multiple bus adapters.
 **    (workstations 1-~4, servers 2-~32)
@@ -35,6 +37,7 @@ struct pci_hba_data {
        struct resource lmmio_space;    /* bus addresses < 4Gb */
        struct resource elmmio_space;   /* additional bus addresses < 4Gb */
        struct resource gmmio_space;    /* bus addresses > 4Gb */
+
        /* NOTE: Dino code assumes it can use *all* of the lmmio_space,
         * elmmio_space and gmmio_space as a contiguous array of
         * resources.  This #define represents the array size */
@@ -43,6 +46,12 @@ struct pci_hba_data {
        unsigned long   lmmio_space_offset;  /* CPU view - PCI view */
        void *          iommu;          /* IOMMU this device is under */
        /* REVISIT - spinlock to protect resources? */
+
+       #define HBA_NAME_SIZE 16
+       char io_name[HBA_NAME_SIZE];
+       char lmmio_name[HBA_NAME_SIZE];
+       char elmmio_name[HBA_NAME_SIZE];
+       char gmmio_name[HBA_NAME_SIZE];
 };
 
 #define HBA_DATA(d)            ((struct pci_hba_data *) (d))
@@ -60,13 +69,36 @@ struct pci_hba_data {
 #define PCI_PORT_HBA(a)                ((a) >> HBA_PORT_SPACE_BITS)
 #define PCI_PORT_ADDR(a)       ((a) & (HBA_PORT_SPACE_SIZE - 1))
 
+#if CONFIG_PARISC64
+#define PCI_F_EXTEND           0xffffffff00000000UL
+#define PCI_IS_LMMIO(hba,a)    pci_is_lmmio(hba,a)
+
+/* We need to know if an address is LMMMIO or GMMIO.
+ * LMMIO requires mangling and GMMIO we must use as-is.
+ */
+static __inline__  int pci_is_lmmio(struct pci_hba_data *hba, unsigned long a)
+{
+       return(((a) & PCI_F_EXTEND) == PCI_F_EXTEND);
+}
+
 /*
 ** Convert between PCI (IO_VIEW) addresses and processor (PA_VIEW) addresses.
-** Note that we currently support only LMMIO.
+** See pcibios.c for more conversions used by Generic PCI code.
 */
-#define PCI_BUS_ADDR(hba,a)    ((a) - hba->lmmio_space_offset)
+#define PCI_BUS_ADDR(hba,a)    (PCI_IS_LMMIO(hba,a)    \
+               ?  ((a) - hba->lmmio_space_offset)      /* mangle LMMIO */ \
+               : (a))                                  /* GMMIO */
 #define PCI_HOST_ADDR(hba,a)   ((a) + hba->lmmio_space_offset)
 
+#else  /* !CONFIG_PARISC64 */
+
+#define PCI_BUS_ADDR(hba,a)    (a)
+#define PCI_HOST_ADDR(hba,a)   (a)
+#define PCI_F_EXTEND           0UL
+#define PCI_IS_LMMIO(hba,a)    (1)     /* 32-bit doesn't support GMMIO */
+
+#endif /* !CONFIG_PARISC64 */
+
 /*
 ** KLUGE: linux/pci.h include asm/pci.h BEFORE declaring struct pci_bus
 ** (This eliminates some of the warnings).
index eb19624..9b19970 100644 (file)
@@ -15,7 +15,7 @@ typedef unsigned short                __kernel_ipc_pid_t;
 typedef unsigned int           __kernel_uid_t;
 typedef unsigned int           __kernel_gid_t;
 typedef int                    __kernel_suseconds_t;
-typedef int                    __kernel_clock_t;
+typedef long                   __kernel_clock_t;
 typedef int                    __kernel_timer_t;
 typedef int                    __kernel_clockid_t;
 typedef int                    __kernel_daddr_t;
index c276c09..22a30e0 100644 (file)
@@ -46,7 +46,8 @@ struct pt_regs {
 #ifdef __KERNEL__
 
 /* XXX should we use iaoq[1] or iaoq[0] ? */
-#define user_mode(regs)                        (((regs)->iaoq[0] &  3) ? 1 : 0)
+#define user_mode(regs)                        (((regs)->iaoq[0] & 3) ? 1 : 0)
+#define user_space(regs)               (((regs)->iasq[0] != 0) ? 1 : 0)
 #define instruction_pointer(regs)      ((regs)->iaoq[0] & ~3)
 #define profile_pc(regs) instruction_pointer(regs)
 extern void show_regs(struct pt_regs *);
index 2f61e97..3fe1212 100644 (file)
@@ -1,3 +1,13 @@
+#ifndef _PA_STRING_H_
+#define _PA_STRING_H_
 
 #define __HAVE_ARCH_MEMSET
 extern void * memset(void *, int, size_t);
+
+#define __HAVE_ARCH_MEMCPY
+void * memcpy(void * dest,const void *src,size_t count);
+
+#define __HAVE_ARCH_BCOPY
+void bcopy(const void * srcp, void * destp, size_t count);
+
+#endif
index 60cac82..c0a04ea 100644 (file)
@@ -87,6 +87,5 @@ extern void superio_inform_irq(int irq);
 extern void superio_serial_init(void);         /* called by rs_init() */
 extern int superio_fixup_irq(struct pci_dev *pcidev); /* called by iosapic */
 extern void superio_fixup_pci(struct pci_dev *pdev);
-extern void superio_ide_init_iops (struct hwif_s *hwif);
 
 #endif /* _PARISC_SUPERIO_H */
index 07c1a9f..e47d890 100644 (file)
@@ -18,12 +18,15 @@ struct thread_info {
 
 #define INIT_THREAD_INFO(tsk)                  \
 {                                              \
-       task:           &tsk,                   \
-       exec_domain:    &default_exec_domain,   \
-       flags:          0,                      \
-       cpu:            0,                      \
-       addr_limit:     KERNEL_DS,              \
-       preempt_count:  0,                      \
+       .task           = &tsk,                 \
+       .exec_domain    = &default_exec_domain, \
+       .flags          = 0,                    \
+       .cpu            = 0,                    \
+       .addr_limit     = KERNEL_DS,            \
+       .preempt_count  = 0,                    \
+       .restart_block  = {                     \
+               .fn = do_no_restart_syscall     \
+       }                                       \
 }
 
 #define init_thread_info        (init_thread_union.thread_info)
index 86ba2c7..eb27b78 100644 (file)
@@ -51,9 +51,12 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
 {
        /* For one page, it's not worth testing the split_tlb variable */
 
+       mb();
        mtsp(vma->vm_mm->context,1);
+       purge_tlb_start();
        pdtlb(addr);
        pitlb(addr);
+       purge_tlb_end();
 }
 
 static inline void flush_tlb_range(struct vm_area_struct *vma,
@@ -61,6 +64,7 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
 {
        unsigned long npages;
 
+       
        npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
        if (npages >= 512)  /* XXX arbitrary, should be tuned */
                flush_tlb_all();
@@ -68,16 +72,20 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
 
                mtsp(vma->vm_mm->context,1);
                if (split_tlb) {
+                       purge_tlb_start();
                        while (npages--) {
                                pdtlb(start);
                                pitlb(start);
                                start += PAGE_SIZE;
                        }
+                       purge_tlb_end();
                } else {
+                       purge_tlb_start();
                        while (npages--) {
                                pdtlb(start);
                                start += PAGE_SIZE;
                        }
+                       purge_tlb_end();
                }
        }
 }
index 861fb92..1311cef 100644 (file)
@@ -92,23 +92,77 @@ typedef struct      mem_ctlr {
        char    res3[0x80];
 } memctl8xx_t;
 
+/*-----------------------------------------------------------------------
+ * BR - Memory Controler: Base Register                                        16-9
+ */
+#define BR_BA_MSK      0xffff8000      /* Base Address Mask                    */
+#define BR_AT_MSK      0x00007000      /* Address Type Mask                    */
+#define BR_PS_MSK      0x00000c00      /* Port Size Mask                       */
+#define BR_PS_32       0x00000000      /* 32 bit port size                     */
+#define BR_PS_16       0x00000800      /* 16 bit port size                     */
+#define BR_PS_8                0x00000400      /*  8 bit port size                     */
+#define BR_PARE                0x00000200      /* Parity Enable                        */
+#define BR_WP          0x00000100      /* Write Protect                        */
+#define BR_MS_MSK      0x000000c0      /* Machine Select Mask                  */
+#define BR_MS_GPCM     0x00000000      /* G.P.C.M. Machine Select              */
+#define BR_MS_UPMA     0x00000080      /* U.P.M.A Machine Select               */
+#define BR_MS_UPMB     0x000000c0      /* U.P.M.B Machine Select               */
+#define BR_V           0x00000001      /* Bank Valid                           */
+
+/*-----------------------------------------------------------------------
+ * OR - Memory Controler: Option Register                              16-11
+ */
+#define OR_AM_MSK      0xffff8000      /* Address Mask Mask                    */
+#define OR_ATM_MSK     0x00007000      /* Address Type Mask Mask               */
+#define OR_CSNT_SAM    0x00000800      /* Chip Select Negation Time/ Start     */
+                                       /* Address Multiplex                    */
+#define OR_ACS_MSK     0x00000600      /* Address to Chip Select Setup mask    */
+#define OR_ACS_DIV1    0x00000000      /* CS is output at the same time        */
+#define OR_ACS_DIV4    0x00000400      /* CS is output 1/4 a clock later       */
+#define OR_ACS_DIV2    0x00000600      /* CS is output 1/2 a clock later       */
+#define OR_G5LA                0x00000400      /* Output #GPL5 on #GPL_A5              */
+#define OR_G5LS                0x00000200      /* Drive #GPL high on falling edge of...*/
+#define OR_BI          0x00000100      /* Burst inhibit                        */
+#define OR_SCY_MSK     0x000000f0      /* Cycle Lenght in Clocks               */
+#define OR_SCY_0_CLK   0x00000000      /* 0 clock cycles wait states           */
+#define OR_SCY_1_CLK   0x00000010      /* 1 clock cycles wait states           */
+#define OR_SCY_2_CLK   0x00000020      /* 2 clock cycles wait states           */
+#define OR_SCY_3_CLK   0x00000030      /* 3 clock cycles wait states           */
+#define OR_SCY_4_CLK   0x00000040      /* 4 clock cycles wait states           */
+#define OR_SCY_5_CLK   0x00000050      /* 5 clock cycles wait states           */
+#define OR_SCY_6_CLK   0x00000060      /* 6 clock cycles wait states           */
+#define OR_SCY_7_CLK   0x00000070      /* 7 clock cycles wait states           */
+#define OR_SCY_8_CLK   0x00000080      /* 8 clock cycles wait states           */
+#define OR_SCY_9_CLK   0x00000090      /* 9 clock cycles wait states           */
+#define OR_SCY_10_CLK  0x000000a0      /* 10 clock cycles wait states          */
+#define OR_SCY_11_CLK  0x000000b0      /* 11 clock cycles wait states          */
+#define OR_SCY_12_CLK  0x000000c0      /* 12 clock cycles wait states          */
+#define OR_SCY_13_CLK  0x000000d0      /* 13 clock cycles wait states          */
+#define OR_SCY_14_CLK  0x000000e0      /* 14 clock cycles wait states          */
+#define OR_SCY_15_CLK  0x000000f0      /* 15 clock cycles wait states          */
+#define OR_SETA                0x00000008      /* External Transfer Acknowledge        */
+#define OR_TRLX                0x00000004      /* Timing Relaxed                       */
+#define OR_EHTR                0x00000002      /* Extended Hold Time on Read           */
+
 /* System Integration Timers.
 */
 typedef struct sys_int_timers {
        ushort  sit_tbscr;
+       char    res0[0x02];
        uint    sit_tbreff0;
        uint    sit_tbreff1;
        char    res1[0x14];
        ushort  sit_rtcsc;
+       char    res2[0x02];
        uint    sit_rtc;
        uint    sit_rtsec;
        uint    sit_rtcal;
-       char    res2[0x10];
+       char    res3[0x10];
        ushort  sit_piscr;
-       char    res3[2];
+       char    res4[2];
        uint    sit_pitc;
        uint    sit_pitr;
-       char    res4[0x34];
+       char    res5[0x34];
 } sit8xx_t;
 
 #define TBSCR_TBIRQ_MASK       ((ushort)0xff00)
@@ -174,20 +228,38 @@ typedef struct cark {
 */
 #define KAPWR_KEY      ((unsigned int)0x55ccaa33)
 
-/* LCD interface.  MPC821 and MPC823 Only.
+/* Video interface.  MPC823 Only.
+*/
+typedef struct vid823 {
+       ushort  vid_vccr;
+       ushort  res1;
+       u_char  vid_vsr;
+       u_char  res2;
+       u_char  vid_vcmr;
+       u_char  res3;
+       uint    vid_vbcb;
+       uint    res4;
+       uint    vid_vfcr0;
+       uint    vid_vfaa0;
+       uint    vid_vfba0;
+       uint    vid_vfcr1;
+       uint    vid_vfaa1;
+       uint    vid_vfba1;
+       u_char  res5[0x18];
+} vid823_t;
+
+/* LCD interface.  823 Only.
 */
 typedef struct lcd {
-       ushort  lcd_lcolr[16];
-       char    res[0x20];
        uint    lcd_lccr;
        uint    lcd_lchcr;
        uint    lcd_lcvcr;
-       char    res2[4];
+       char    res1[4];
        uint    lcd_lcfaa;
        uint    lcd_lcfba;
        char    lcd_lcsr;
-       char    res3[0x7];
-} lcd8xx_t;
+       char    res2[0x7];
+} lcd823_t;
 
 /* I2C
 */
@@ -254,7 +326,8 @@ typedef struct io_port {
        ushort  iop_pdpar;
        char    res3[2];
        ushort  iop_pddat;
-       char    res4[8];
+       uint    utmode;
+       char    res4[4];
 } iop8xx_t;
 
 /* Communication Processor Module Timers
@@ -290,7 +363,7 @@ typedef struct cpm_timers {
 typedef struct scc {           /* Serial communication channels */
        uint    scc_gsmrl;
        uint    scc_gsmrh;
-       ushort  scc_pmsr;
+       ushort  scc_psmr;
        char    res1[2];
        ushort  scc_todr;
        ushort  scc_dsr;
@@ -315,41 +388,44 @@ typedef struct smc {              /* Serial management channels */
 /* MPC860T Fast Ethernet Controller.  It isn't part of the CPM, but
  * it fits within the address space.
  */
+
 typedef struct fec {
-       uint    fec_addr_low;           /* LS 32 bits of station address */
-       ushort  fec_addr_high;          /* MS 16 bits of address */
-       ushort  res1;
-       uint    fec_hash_table_high;
-       uint    fec_hash_table_low;
-       uint    fec_r_des_start;
-       uint    fec_x_des_start;
-       uint    fec_r_buff_size;
-       uint    res2[9];
-       uint    fec_ecntrl;
-       uint    fec_ievent;
-       uint    fec_imask;
-       uint    fec_ivec;
-       uint    fec_r_des_active;
-       uint    fec_x_des_active;
-       uint    res3[10];
-       uint    fec_mii_data;
-       uint    fec_mii_speed;
-       uint    res4[17];
-       uint    fec_r_bound;
-       uint    fec_r_fstart;
-       uint    res5[6];
-       uint    fec_x_fstart;
-       uint    res6[17];
-       uint    fec_fun_code;
-       uint    res7[3];
-       uint    fec_r_cntrl;
-       uint    fec_r_hash;
-       uint    res8[14];
-       uint    fec_x_cntrl;
-       uint    res9[0x1e];
+       uint    fec_addr_low;           /* lower 32 bits of station address     */
+       ushort  fec_addr_high;          /* upper 16 bits of station address     */
+       ushort  res1;                   /* reserved                             */
+       uint    fec_hash_table_high;    /* upper 32-bits of hash table          */
+       uint    fec_hash_table_low;     /* lower 32-bits of hash table          */
+       uint    fec_r_des_start;        /* beginning of Rx descriptor ring      */
+       uint    fec_x_des_start;        /* beginning of Tx descriptor ring      */
+       uint    fec_r_buff_size;        /* Rx buffer size                       */
+       uint    res2[9];                /* reserved                             */
+       uint    fec_ecntrl;             /* ethernet control register            */
+       uint    fec_ievent;             /* interrupt event register             */
+       uint    fec_imask;              /* interrupt mask register              */
+       uint    fec_ivec;               /* interrupt level and vector status    */
+       uint    fec_r_des_active;       /* Rx ring updated flag                 */
+       uint    fec_x_des_active;       /* Tx ring updated flag                 */
+       uint    res3[10];               /* reserved                             */
+       uint    fec_mii_data;           /* MII data register                    */
+       uint    fec_mii_speed;          /* MII speed control register           */
+       uint    res4[17];               /* reserved                             */
+       uint    fec_r_bound;            /* end of RAM (read-only)               */
+       uint    fec_r_fstart;           /* Rx FIFO start address                */
+       uint    res5[6];                /* reserved                             */
+       uint    fec_x_fstart;           /* Tx FIFO start address                */
+       uint    res6[17];               /* reserved                             */
+       uint    fec_fun_code;           /* fec SDMA function code               */
+       uint    res7[3];                /* reserved                             */
+       uint    fec_r_cntrl;            /* Rx control register                  */
+       uint    fec_r_hash;             /* Rx hash register                     */
+       uint    res8[14];               /* reserved                             */
+       uint    fec_x_cntrl;            /* Tx control register                  */
+       uint    res9[0x1e];             /* reserved                             */
 } fec_t;
 
-/* We need this as the fec and fb cmap use the same address space */
+/* The FEC and LCD color map share the same address space....
+ * I guess we will never see an 823T :-).
+ */
 union fec_lcd {
        fec_t   fl_un_fec;
        u_char  fl_un_cmap[0x200];
@@ -359,18 +435,20 @@ typedef struct comm_proc {
        /* General control and status registers.
        */
        ushort  cp_cpcr;
-       char    res1[2];
+       u_char  res1[2];
        ushort  cp_rccr;
-       char    res2[6];
+       u_char  res2;
+       u_char  cp_rmds;
+       u_char  res3[4];
        ushort  cp_cpmcr1;
        ushort  cp_cpmcr2;
        ushort  cp_cpmcr3;
        ushort  cp_cpmcr4;
-       char    res3[2];
+       u_char  res4[2];
        ushort  cp_rter;
-       char    res4[2];
+       u_char  res5[2];
        ushort  cp_rtmr;
-       char    res5[0x14];
+       u_char  res6[0x14];
 
        /* Baud rate generators.
        */
@@ -390,56 +468,75 @@ typedef struct comm_proc {
        /* Serial Peripheral Interface.
        */
        ushort  cp_spmode;
-       char    res6[4];
+       u_char  res7[4];
        u_char  cp_spie;
-       char    res7[3];
+       u_char  res8[3];
        u_char  cp_spim;
-       char    res8[2];
+       u_char  res9[2];
        u_char  cp_spcom;
-       char    res9[2];
+       u_char  res10[2];
 
        /* Parallel Interface Port.
        */
-       char    res10[2];
+       u_char  res11[2];
        ushort  cp_pipc;
-       char    res11[2];
+       u_char  res12[2];
        ushort  cp_ptpr;
        uint    cp_pbdir;
        uint    cp_pbpar;
-       char    res12[2];
+       u_char  res13[2];
        ushort  cp_pbodr;
        uint    cp_pbdat;
-       char    res13[0x18];
+
+       /* Port E - MPC87x/88x only.
+        */
+       uint    cp_pedir;
+       uint    cp_pepar;
+       uint    cp_peso;
+       uint    cp_peodr;
+       uint    cp_pedat;
+
+       /* Communications Processor Timing Register -
+          Contains RMII Timing for the FECs on MPC87x/88x only.
+       */
+       uint    cp_cptr;
 
        /* Serial Interface and Time Slot Assignment.
        */
        uint    cp_simode;
        u_char  cp_sigmr;
-       char    res14;
+       u_char  res15;
        u_char  cp_sistr;
        u_char  cp_sicmr;
-       char    res15[4];
+       u_char  res16[4];
        uint    cp_sicr;
        uint    cp_sirp;
-       char    res16[0x10c];
+       u_char  res17[0xc];
+
+       /* 256 bytes of MPC823 video controller RAM array.
+       */
+       u_char  cp_vcram[0x100];
        u_char  cp_siram[0x200];
 
        /* The fast ethernet controller is not really part of the CPM,
         * but it resides in the address space.
-        *
-        * The colormap for the LCD controller is also located here
+        * The LCD color map is also here.
         */
-       union   fec_lcd fl_un;
-#define cp_fec fl_un.fl_un_fec
-#define lcd_cmap fl_un.fl_un_cmap
-       char    res18[0x1000];
+       union   fec_lcd fl_un;
+#define cp_fec         fl_un.fl_un_fec
+#define lcd_cmap       fl_un.fl_un_cmap
+       char    res18[0xE00];
+
+       /* The DUET family has a second FEC here */
+       fec_t   cp_fec2;
+#define cp_fec1        cp_fec  /* consistency macro */
 
        /* Dual Ported RAM follows.
         * There are many different formats for this memory area
         * depending upon the devices used and options chosen.
+        * Some processors don't have all of it populated.
         */
-       u_char  cp_dpmem[0x1000];       /* BD / Data / ucode */
-       u_char  res19[0xc00];
+       u_char  cp_dpmem[0x1C00];       /* BD / Data / ucode */
        u_char  cp_dparam[0x400];       /* Parameter RAM */
 } cpm8xx_t;
 
@@ -453,7 +550,8 @@ typedef struct immap {
        car8xx_t        im_clkrst;      /* Clocks and reset */
        sitk8xx_t       im_sitk;        /* Sys int timer keys */
        cark8xx_t       im_clkrstk;     /* Clocks and reset keys */
-       lcd8xx_t        im_lcd;         /* LCD (821 and 823 only) */
+       vid823_t        im_vid;         /* Video (823 only) */
+       lcd823_t        im_lcd;         /* LCD (823 only) */
        i2c8xx_t        im_i2c;         /* I2C control/status */
        sdma8xx_t       im_sdma;        /* SDMA control/status */
        cpic8xx_t       im_cpic;        /* CPM Interrupt Controller */
index fcdb87d..34f37ab 100644 (file)
@@ -21,6 +21,9 @@
 #define PPC_FEATURE_HAS_MMU            0x04000000
 #define PPC_FEATURE_HAS_4xxMAC         0x02000000
 #define PPC_FEATURE_UNIFIED_CACHE      0x01000000
+#define PPC_FEATURE_HAS_SPE            0x00800000
+#define PPC_FEATURE_HAS_EFP_SINGLE     0x00400000
+#define PPC_FEATURE_HAS_EFP_DOUBLE     0x00200000
 
 #ifdef __KERNEL__
 
@@ -46,6 +49,9 @@ struct cpu_spec {
        unsigned int    icache_bsize;
        unsigned int    dcache_bsize;
 
+       /* number of performance monitor counters */
+       unsigned int    num_pmcs;
+
        /* this is called to initialize various CPU bits like L1 cache,
         * BHT, SPD, etc... from head.S before branching to identify_machine
         */
index dfb8472..94f1411 100644 (file)
@@ -21,46 +21,11 @@ typedef struct {
 
 #define last_jiffy_stamp(cpu) __IRQ_STAT((cpu), __last_jiffy_stamp)
 
-/*
- * 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
-#define HARDIRQ_BITS   8
-
-#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 irq_exit()                                                     \
-do {                                                                   \
-       preempt_count() -= IRQ_EXIT_OFFSET;                             \
-       if (!in_interrupt() && softirq_pending(smp_processor_id()))     \
-               do_softirq();                                           \
-       preempt_enable_no_resched();                                    \
-} while (0)
+static inline void ack_bad_irq(int irq)
+{
+       printk(KERN_CRIT "illegal vector %d received!\n", irq);
+       BUG();
+}
 
 #endif /* __ASM_HARDIRQ_H */
 #endif /* __KERNEL__ */
index 5e5a408..47dc799 100644 (file)
@@ -9,7 +9,6 @@
 #include <asm/reg.h>
 
 extern void timer_interrupt(struct pt_regs *);
-extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
 
 #define INLINE_IRQS
 
index d3be235..a046ce2 100644 (file)
@@ -81,6 +81,7 @@ extern unsigned char __res[];
 #define MPC85xx_IRQ_DUART      (26 + MPC85xx_OPENPIC_IRQ_OFFSET)
 #define MPC85xx_IRQ_IIC1       (27 + MPC85xx_OPENPIC_IRQ_OFFSET)
 #define MPC85xx_IRQ_PERFMON    (28 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_SEC2       (29 + MPC85xx_OPENPIC_IRQ_OFFSET)
 #define MPC85xx_IRQ_CPM                (30 + MPC85xx_OPENPIC_IRQ_OFFSET)
 
 /* The 12 external interrupt lines */
@@ -120,6 +121,8 @@ extern unsigned char __res[];
 #define MPC85xx_PCI2_SIZE      (0x01000)
 #define MPC85xx_PERFMON_OFFSET (0xe1000)
 #define MPC85xx_PERFMON_SIZE   (0x01000)
+#define MPC85xx_SEC2_OFFSET    (0x30000)
+#define MPC85xx_SEC2_SIZE      (0x10000)
 #define MPC85xx_UART0_OFFSET   (0x04500)
 #define MPC85xx_UART0_SIZE     (0x00100)
 #define MPC85xx_UART1_OFFSET   (0x04600)
index 4aa8b15..714d69c 100644 (file)
 extern unsigned char __res[];
 
 struct pt_regs;
-extern int request_8xxirq(unsigned int irq,
-                      void (*handler)(int, void *, struct pt_regs *),
-                      unsigned long flags,
-                      const char *device,
-                      void *dev_id);
+
 #endif /* !__ASSEMBLY__ */
 #endif /* CONFIG_8xx */
 #endif /* __CONFIG_8xx_DEFS */
index 289761f..cc238f5 100644 (file)
@@ -36,6 +36,7 @@ extern struct hw_interrupt_type open_pic_ipi;
 extern u_int OpenPIC_NumInitSenses;
 extern u_char *OpenPIC_InitSenses;
 extern void* OpenPIC_Addr;
+extern int epic_serial_mode;
 
 /* Exported functions */
 extern void openpic_set_sources(int first_irq, int num_irqs, void *isr);
@@ -54,6 +55,7 @@ extern void openpic_cause_IPI(u_int ipi, cpumask_t cpumask);
 extern void smp_openpic_message_pass(int target, int msg, unsigned long data,
                                     int wait);
 extern void openpic_set_k2_cascade(int irq);
+extern void openpic_set_priority(u_int pri);
 
 extern inline int openpic_to_irq(int irq)
 {
index acd9cb4..dc61c91 100644 (file)
@@ -94,6 +94,8 @@ int early_write_config_word(struct pci_controller *hose, int bus, int dev_fn,
 int early_write_config_dword(struct pci_controller *hose, int bus, int dev_fn,
                             int where, u32 val);
 
+extern void setup_indirect_pci_nomap(struct pci_controller* hose,
+                              u32 cfg_addr, u32 cfg_data);
 extern void setup_indirect_pci(struct pci_controller* hose,
                               u32 cfg_addr, u32 cfg_data);
 extern void setup_grackle(struct pci_controller *hose);
index 340235d..c39b6ce 100644 (file)
@@ -65,7 +65,7 @@ static inline struct thread_info *current_thread_info(void)
  */
 #define THREAD_SIZE            8192    /* 2 pages */
 
-#define PREEMPT_ACTIVE         0x4000000
+#define PREEMPT_ACTIVE         0x10000000
 
 /*
  * thread information flag bit numbers
index 73f4fcd..ce09b47 100644 (file)
@@ -10,7 +10,8 @@
 #define __ASM_TIME_H__
 
 #include <linux/config.h>
-#include <linux/mc146818rtc.h>
+#include <linux/types.h>
+#include <linux/rtc.h>
 #include <linux/threads.h>
 
 #include <asm/reg.h>
index 65192b7..b9bffff 100644 (file)
 #include <asm/cputable.h>
 
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
-#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)
 
 typedef unsigned long cycles_t;
 
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
index c25d095..5c497b5 100644 (file)
@@ -11,6 +11,7 @@
 #define __ASM_PPC64_FLOPPY_H
 
 #include <linux/config.h>
+#include <asm/machdep.h>
 
 #define fd_inb(port)                   inb_p(port)
 #define fd_outb(value,port)            outb_p(value,port)
index ef49702..2e59a8e 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * mf.h
  * Copyright (C) 2001  Troy D. Armstrong IBM Corporation
+ * Copyright (C) 2004  Stephen Rothwell IBM Corporation
  *
  * This modules exists as an interface between a Linux secondary partition
  * running on an iSeries and the primary partition's Virtual Service
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
-#ifndef MF_H_INCLUDED
-#define MF_H_INCLUDED
+#ifndef _ASM_PPC64_ISERIES_MF_H
+#define _ASM_PPC64_ISERIES_MF_H
 
-#include <linux/proc_fs.h>
+#include <linux/types.h>
 
 #include <asm/iSeries/HvTypes.h>
-#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/HvCallEvent.h>
 
 struct rtc_time;
 
 typedef void (*MFCompleteHandler)(void *clientToken, int returnCode);
 
-extern void mf_allocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
+extern void mf_allocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type,
                unsigned size, unsigned amount, MFCompleteHandler hdlr,
                void *userToken);
-extern void mf_deallocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
+extern void mf_deallocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type,
                unsigned count, MFCompleteHandler hdlr, void *userToken);
 
-extern void mf_powerOff(void);
+extern void mf_power_off(void);
 extern void mf_reboot(void);
 
-extern void mf_displaySrc(u32 word);
-extern void mf_displayProgress(u16 value);
-extern void mf_clearSrc(void);
+extern void mf_display_src(u32 word);
+extern void mf_display_progress(u16 value);
+extern void mf_clear_src(void);
 
 extern void mf_init(void);
 
-extern void mf_setSide(char side);
-extern char mf_getSide(void);
+extern int mf_get_rtc(struct rtc_time *tm);
+extern int mf_set_rtc(struct rtc_time *tm);
 
-extern void mf_setCmdLine(const char *cmdline, int size, u64 side);
-extern int  mf_getCmdLine(char *cmdline, int *size, u64 side);
-
-extern void mf_getSrcHistory(char *buffer, int size);
-
-extern int mf_setVmlinuxChunk(const char *buffer, int size, int offset,
-               u64 side);
-extern int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side);
-
-extern int mf_setRtcTime(unsigned long time);
-extern int mf_getRtcTime(unsigned long *time);
-extern int mf_getRtc( struct rtc_time * tm );
-extern int mf_setRtc( struct rtc_time * tm );
-
-#endif /* MF_H_INCLUDED */
+#endif /* _ASM_PPC64_ISERIES_MF_H */
index 17452d3..f4a5fb7 100644 (file)
@@ -22,12 +22,14 @@ static inline long cede_processor(void)
        return(0); 
 }
 
-static inline long register_vpa(unsigned long flags, unsigned long proc, unsigned long vpa)
+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); 
+       return plpar_hcall_norets(H_REGISTER_VPA, flags, proc, vpa);
 }
 
+void vpa_init(int cpu);
+
 static inline long plpar_pte_remove(unsigned long flags,
                                    unsigned long ptex,
                                    unsigned long avpn,
index edf5886..d6bcb79 100644 (file)
@@ -4,8 +4,6 @@
 #ifndef _PPC64_SERIAL_H
 #define _PPC64_SERIAL_H
 
-#include <linux/config.h>
-
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
  *
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#define BASE_BAUD ( 1843200 / 16 )
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE  64
-#else
-#define RS_TABLE_SIZE  4
-#endif
-
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
-#endif
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-       
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
 
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-#define STD_SERIAL_PORT_DEFNS                  \
-       /* 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, 0x890, 0xf, STD_COM_FLAGS },    /* ttyS2 */     \
-       { 0, BASE_BAUD, 0x898, 0xe, STD_COM_FLAGS },    /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS                        \
-       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
-       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare) */            \
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare) */            \
-       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
-       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
-       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
-       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
-       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
-       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
-       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
-       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
-       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
-       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
-       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
-       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
-       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
-       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
-       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
-       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS          \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },  /* ttyS32 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },  /* ttyS33 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },  /* ttyS34 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },  /* ttyS35 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },  /* ttyS36 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },  /* ttyS37 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },  /* ttyS38 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },  /* ttyS39 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },  /* ttyS40 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },  /* ttyS41 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },  /* ttyS42 */ \
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },  /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
-#define MCA_SERIAL_PORT_DFNS
-
-#define SERIAL_PORT_DFNS               \
-       STD_SERIAL_PORT_DEFNS           \
-       EXTRA_SERIAL_PORT_DEFNS         \
-       HUB6_SERIAL_PORT_DFNS           \
-       MCA_SERIAL_PORT_DFNS
+/* Default baud base if not found in device-tree */
+#define BASE_BAUD ( 1843200 / 16 )
 
 #endif /* _PPC64_SERIAL_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);
index cb7149a..8db4da4 100644 (file)
 #define _ASMPPC64_TIMEX_H
 
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
-#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)
 
 typedef unsigned long cycles_t;
 
index c6846ec..ed630fc 100644 (file)
@@ -37,8 +37,25 @@ static inline int node_to_first_cpu(int node)
 
 #define nr_cpus_node(node)     (nr_cpus_in_node[node])
 
-/* Cross-node load balancing interval. */
-#define NODE_BALANCE_RATE 10
+/* sched_domains SD_NODE_INIT for PPC64 machines */
+#define SD_NODE_INIT (struct sched_domain) {           \
+       .span                   = CPU_MASK_NONE,        \
+       .parent                 = NULL,                 \
+       .groups                 = NULL,                 \
+       .min_interval           = 8,                    \
+       .max_interval           = 32,                   \
+       .busy_factor            = 32,                   \
+       .imbalance_pct          = 125,                  \
+       .cache_hot_time         = (10*1000),            \
+       .cache_nice_tries       = 1,                    \
+       .per_cpu_gain           = 100,                  \
+       .flags                  = SD_LOAD_BALANCE       \
+                               | SD_BALANCE_EXEC       \
+                               | SD_WAKE_BALANCE,      \
+       .last_balance           = jiffies,              \
+       .balance_interval       = 1,                    \
+       .nr_balance_failed      = 0,                    \
+}
 
 #else /* !CONFIG_NUMA */
 
index 3a145e1..c8802c9 100644 (file)
@@ -8,12 +8,25 @@
 #ifndef _ASM_S390X_DCSS_H
 #define _ASM_S390X_DCSS_H
 #ifndef __ASSEMBLY__
-#define SEGMENT_SHARED_RW       0
-#define SEGMENT_SHARED_RO       1
-#define SEGMENT_EXCLUSIVE_RW    2
-#define SEGMENT_EXCLUSIVE_RO    3
+
+/* possible values for segment type as returned by segment_info */
+#define SEG_TYPE_SW 0
+#define SEG_TYPE_EW 1
+#define SEG_TYPE_SR 2
+#define SEG_TYPE_ER 3
+#define SEG_TYPE_SN 4
+#define SEG_TYPE_EN 5
+#define SEG_TYPE_SC 6
+#define SEG_TYPE_EWEN 7
+
+#define SEGMENT_SHARED 0
+#define SEGMENT_EXCLUSIVE 1
+
 extern int segment_load (char *name,int segtype,unsigned long *addr,unsigned long *length);
 extern void segment_unload(char *name);
-extern void segment_replace(char *name);
+extern void segment_save(char *name);
+extern int segment_type (char* name);
+extern int segment_modify_shared (char *name, int do_nonshared);
+
 #endif
 #endif
index 363b0a8..05670c2 100644 (file)
@@ -38,29 +38,8 @@ softirq_pending(unsigned int cpu)
 
 #define __ARCH_IRQ_STAT
 
-/*
- * 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
 #define HARDIRQ_BITS   8
 
-#define PREEMPT_SHIFT  0
-#define SOFTIRQ_SHIFT  (PREEMPT_SHIFT + PREEMPT_BITS)
-#define HARDIRQ_SHIFT  (SOFTIRQ_SHIFT + SOFTIRQ_BITS)
-
 extern void account_ticks(struct pt_regs *);
 
 #define __ARCH_HAS_DO_SOFTIRQ
index de73122..60342a5 100644 (file)
@@ -105,6 +105,8 @@ extern void iounmap(void *addr);
 #define outb(x,addr) ((void) writeb(x,addr))
 #define outb_p(x,addr) outb(x,addr)
 
+#define mmiowb()
+
 #endif /* __KERNEL__ */
 
 #endif
index 446fa8c..7230353 100644 (file)
@@ -9,7 +9,6 @@
 #ifndef _S390_SIGINFO_H
 #define _S390_SIGINFO_H
 
-#define HAVE_ARCH_SI_CODES
 #ifdef __s390x__
 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
 #endif
 
 #include <asm-generic/siginfo.h>
 
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC     (__SI_FAULT|1)  /* illegal opcode */
-#define ILL_ILLOPN     (__SI_FAULT|2)  /* illegal operand */
-#define ILL_ILLADR     (__SI_FAULT|3)  /* illegal addressing mode */
-#define ILL_ILLTRP     (__SI_FAULT|4)  /* illegal trap */
-#define ILL_PRVOPC     (__SI_FAULT|5)  /* privileged opcode */
-#define ILL_PRVREG     (__SI_FAULT|6)  /* privileged register */
-#define ILL_COPROC     (__SI_FAULT|7)  /* coprocessor error */
-#define ILL_BADSTK     (__SI_FAULT|8)  /* internal stack error */
-#define NSIGILL                8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV     (__SI_FAULT|1)  /* integer divide by zero */
-#define FPE_INTOVF     (__SI_FAULT|2)  /* integer overflow */
-#define FPE_FLTDIV     (__SI_FAULT|3)  /* floating point divide by zero */
-#define FPE_FLTOVF     (__SI_FAULT|4)  /* floating point overflow */
-#define FPE_FLTUND     (__SI_FAULT|5)  /* floating point underflow */
-#define FPE_FLTRES     (__SI_FAULT|6)  /* floating point inexact result */
-#define FPE_FLTINV     (__SI_FAULT|7)  /* floating point invalid operation */
-#define FPE_FLTSUB     (__SI_FAULT|8)  /* subscript out of range */
-#define NSIGFPE                8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR    (__SI_FAULT|1)  /* address not mapped to object */
-#define SEGV_ACCERR    (__SI_FAULT|2)  /* invalid permissions for mapped object */
-#define NSIGSEGV       2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN     (__SI_FAULT|1)  /* invalid address alignment */
-#define BUS_ADRERR     (__SI_FAULT|2)  /* non-existant physical address */
-#define BUS_OBJERR     (__SI_FAULT|3)  /* object specific hardware error */
-#define NSIGBUS                3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT     (__SI_FAULT|1)  /* process breakpoint */
-#define TRAP_TRACE     (__SI_FAULT|2)  /* process trace trap */
-#define NSIGTRAP       2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED     (__SI_CHLD|1)   /* child has exited */
-#define CLD_KILLED     (__SI_CHLD|2)   /* child was killed */
-#define CLD_DUMPED     (__SI_CHLD|3)   /* child terminated abnormally */
-#define CLD_TRAPPED    (__SI_CHLD|4)   /* traced child has trapped */
-#define CLD_STOPPED    (__SI_CHLD|5)   /* child has stopped */
-#define CLD_CONTINUED  (__SI_CHLD|6)   /* stopped child has continued */
-#define NSIGCHLD       6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN                (__SI_POLL|1)   /* data input available */
-#define POLL_OUT       (__SI_POLL|2)   /* output buffers available */
-#define POLL_MSG       (__SI_POLL|3)   /* input message available */
-#define POLL_ERR       (__SI_POLL|4)   /* i/o error */
-#define POLL_PRI       (__SI_POLL|5)   /* high priority input available */
-#define POLL_HUP       (__SI_POLL|6)   /* device disconnected */
-#define NSIGPOLL       6
-
 #endif
index 226acd0..c878d6a 100644 (file)
 #define _ASM_S390_TIMEX_H
 
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
-#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)
 
 typedef unsigned long long cycles_t;
 
index 190986c..dbb05d1 100644 (file)
@@ -9,6 +9,7 @@
  */
 #ifndef __ASM_SH_ADDRSPACE_H
 #define __ASM_SH_ADDRSPACE_H
+#ifdef __KERNEL__
 
 #include <asm/cpu/addrspace.h>
 
@@ -33,4 +34,5 @@
 #define P3SEGADDR(a)   ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG))
 #define P4SEGADDR(a)   ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG))
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_SH_ADDRSPACE_H */
index edd9326..1805534 100644 (file)
@@ -212,7 +212,7 @@ static __inline__ unsigned long __ffs(unsigned long word)
  * @offset: The bitnumber to start searching at
  * @size: The maximum size to search
  */
-static __inline__ unsigned long find_next_bit(unsigned long *addr,
+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);
@@ -344,7 +344,7 @@ static inline int sched_find_first_bit(unsigned long *b)
 #define ext2_test_bit(nr, addr) test_bit((nr), (addr))
 #define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
 #define ext2_find_next_zero_bit(addr, size, offset) \
-                find_next_zero_bit((addr), (size), (offset))
+                find_next_zero_bit((unsigned long *)(addr), (size), (offset))
 #else
 static __inline__ int ext2_set_bit(int nr, volatile void * addr)
 {
index 88eb053..406aa8d 100644 (file)
 #define CCR_CACHE_ENABLE       CCR_CACHE_CE
 #define CCR_CACHE_INVALIDATE   CCR_CACHE_CF
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#define CCR3   0xa40000b4
+#define CCR_CACHE_16KB  0x00010000
+#define CCR_CACHE_32KB 0x00020000
+#endif
+
+
 #endif /* __ASM_CPU_SH3_CACHE_H */
 
index 2161faa..201d94f 100644 (file)
 #ifndef __ASM_CPU_SH4_FREQ_H
 #define __ASM_CPU_SH4_FREQ_H
 
+#if defined(CONFIG_CPU_SUBTYPE_SH73180)
+#define FRQCR                  0xa4150000
+#else
 #define FRQCR                  0xffc00000
+#endif
 #define MIN_DIVISOR_NR         0
 #define MAX_DIVISOR_NR         3
 
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 */
index 79cce6c..2c0fde4 100644 (file)
@@ -10,6 +10,7 @@
  */
 #ifndef __ASM_SH_FREQ_H
 #define __ASM_SH_FREQ_H
+#ifdef __KERNEL__
 
 #include <asm/cpu/freq.h>
 
@@ -24,5 +25,5 @@ extern unsigned int get_ifc_value(unsigned int divisor);
 extern unsigned int get_pfc_value(unsigned int divisor);
 extern unsigned int get_bfc_value(unsigned int divisor);
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_SH_FREQ_H */
-
index 1d7135a..f63336a 100644 (file)
@@ -12,29 +12,8 @@ typedef struct {
 
 #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
 #define HARDIRQ_BITS   8
 
-#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
index 09b2a54..ab5f401 100644 (file)
 #define readw_relaxed(a) readw(a)
 #define readl_relaxed(a) readl(a)
 
+#define mmiowb()
+
 /*
  * If the platform has PC-like I/O, this function converts the offset into
  * an address.
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 */
index c956dde..6760d06 100644 (file)
@@ -6,6 +6,7 @@
  */
 #ifndef __ASM_SH_MMU_CONTEXT_H
 #define __ASM_SH_MMU_CONTEXT_H
+#ifdef __KERNEL__
 
 #include <asm/cpu/mmu_context.h>
 #include <asm/tlbflush.h>
@@ -201,4 +202,5 @@ static inline void disable_mmu(void)
 #define disable_mmu()  do { BUG(); } while (0)
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_SH_MMU_CONTEXT_H */
index ddc20db..cea9cdf 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_RTC_H
 #define _ASM_RTC_H
+#ifdef __KERNEL__
 
 #include <asm/machvec.h>
 #include <asm/cpu/rtc.h>
@@ -24,5 +25,5 @@ extern int (*rtc_set_time)(const time_t);
 #define RCR2_RESET     0x02    /* Reset bit               */
 #define RCR2_START     0x01    /* Start bit               */
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_RTC_H */
-
index 8aafb71..791c5da 100644 (file)
 #define PA_DIPSW0      0xb0800000      /* Dip switch 5,6 */
 #define PA_DIPSW1      0xb0800002      /* Dip switch 7,8 */
 #define PA_LED         0xb0c00000      /* LED */
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#define PA_BCR         0xb0e00000
+#else
 #define PA_BCR         0xb1400000      /* FPGA */
+#endif
 
 #define PA_MRSHPC      0xb83fffe0      /* MR-SHPC-01 PCMCIA controller */
 #define PA_MRSHPC_MW1  0xb8400000      /* MR-SHPC-01 memory window base */
 #define BCR_ILCRF      (PA_BCR + 10)
 #define BCR_ILCRG      (PA_BCR + 12)
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#define IRQ_STNIC   12
+#else
 #define IRQ_STNIC      10
+#endif
 
 #endif  /* __ASM_SH_HITACHI_SE_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 */
index 93a90b1..0a95604 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_SH_SHMPARAM_H
 #define __ASM_SH_SHMPARAM_H
+#ifdef __KERNEL__
 
 #include <asm/cpu/shmparam.h>
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_SH_SHMPARAM_H */
index 31498c9..5e67caf 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/kernel.h>
 
 /*
  *     switch_to() should switch tasks to task nr n, first
index a4a70df..3bac2a5 100644 (file)
@@ -25,16 +25,6 @@ struct thread_info {
        __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_CPU         0x0000000c
-#define TI_PRE_COUNT   0x00000010
-#define TI_RESTART_BLOCK 0x00000014
-
 #endif
 
 #define PREEMPT_ACTIVE         0x4000000
index 96a33d1..bd2f435 100644 (file)
@@ -7,10 +7,6 @@
 #define __ASM_SH_TIMEX_H
 
 #define CLOCK_TICK_RATE                (CONFIG_SH_PCLK_FREQ / 4) /* Underlying HZ */
-#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)
 
 typedef unsigned long long cycles_t;
 
index 78b798e..d1b8511 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef __ASM_SH_USER_H
 #define __ASM_SH_USER_H
 
-#include <linux/types.h>
-#include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/page.h>
 
index ff05517..f0cf4be 100644 (file)
@@ -10,6 +10,7 @@
  */
 #ifndef __ASM_SH_WATCHDOG_H
 #define __ASM_SH_WATCHDOG_H
+#ifdef __KERNEL__
 
 #include <linux/types.h>
 #include <linux/config.h>
@@ -106,5 +107,5 @@ static inline void sh_wdt_write_csr(__u8 val)
        ctrl_outw((WTCSR_HIGH << 8) | (__u16)val, WTCSR);
 }
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_SH_WATCHDOG_H */
-
index 8e99f5b..2703207 100644 (file)
@@ -86,6 +86,9 @@ static inline void sh64_out64(unsigned long long b, unsigned long addr)
 #define readb(addr)            sh64_in8(addr)
 #define readw(addr)            sh64_in16(addr)
 #define readl(addr)            sh64_in32(addr)
+#define readb_relaxed(addr)            sh64_in8(addr)
+#define readw_relaxed(addr)            sh64_in16(addr)
+#define readl_relaxed(addr)            sh64_in32(addr)
 
 #define writeb(b, addr)                sh64_out8(b, addr)
 #define writew(b, addr)                sh64_out16(b, addr)
@@ -106,6 +109,8 @@ void outb(unsigned long value, unsigned long port);
 void outw(unsigned long value, unsigned long port);
 void outl(unsigned long value, unsigned long port);
 
+#define mmiowb()
+
 #ifdef __KERNEL__
 
 #ifdef CONFIG_SH_CAYMAN
index 1f333c1..d9e015e 100644 (file)
@@ -479,7 +479,8 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
 #define PageSkip(page)         (0)
 #define kern_addr_valid(addr)  (1)
 
-#define io_remap_page_range remap_page_range
+#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
+               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 #endif /* !__ASSEMBLY__ */
 
 /*
index 2b2a519..d178642 100644 (file)
@@ -143,7 +143,7 @@ typedef struct {
    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         (0x08000000)
+#define ELF_ET_DYN_BASE         (TASK_UNMAPPED_BASE)
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this cpu supports.  This can NOT be done in userspace
index 5b0194e..8c01c5f 100644 (file)
 
 #define        ENOMEDIUM       125     /* No medium found */
 #define        EMEDIUMTYPE     126     /* Wrong medium type */
+#define        ECANCELED       127     /* Operation Cancelled */
+#define        ENOKEY          128     /* Required key not available */
+#define        EKEYEXPIRED     129     /* Key has expired */
+#define        EKEYREVOKED     130     /* Key has been revoked */
+#define        EKEYREJECTED    131     /* Key was rejected by service */
 
 #endif
index 68834d3..c2b27e7 100644 (file)
@@ -53,9 +53,9 @@ struct  fbtype {
 struct  fbcmap {
         int             index;          /* first element (0 origin) */
         int             count;
-        unsigned char   *red;
-        unsigned char   *green;
-        unsigned char   *blue;
+        unsigned char   __user *red;
+        unsigned char   __user *green;
+        unsigned char   __user *blue;
 };
 
 #ifdef __KERNEL__
index 30328ee..529dc93 100644 (file)
@@ -23,89 +23,82 @@ static inline u16 flip_word (u16 w)
        return ((w&0xff) << 8) | ((w>>8)&0xff);
 }
 
+#define mmiowb()
+
 /*
  * Memory mapped I/O to PCI
- *
- * Observe that ioremap returns void* cookie, but accessors, such
- * as readb, take unsigned long as address, by API. This mismatch
- * happened historically. The ioremap is much older than accessors,
- * so at one time ioremap's cookie was used as address (*a = val).
- * When accessors came about, they were designed to be compatible across
- * buses, so that drivers can select proper ones like sunhme.c did.
- * To make that easier, they use same aruments (ulong) for sbus, pci, isa.
- * The offshot is, we must cast readb et. al. arguments with a #define.
  */
 
-static inline u8 __raw_readb(unsigned long addr)
+static inline u8 __raw_readb(const volatile void __iomem *addr)
 {
-       return *(volatile u8 *)addr;
+       return *(__force volatile u8 *)addr;
 }
 
-static inline u16 __raw_readw(unsigned long addr)
+static inline u16 __raw_readw(const volatile void __iomem *addr)
 {
-       return *(volatile u16 *)addr;
+       return *(__force volatile u16 *)addr;
 }
 
-static inline u32 __raw_readl(unsigned long addr)
+static inline u32 __raw_readl(const volatile void __iomem *addr)
 {
-       return *(volatile u32 *)addr;
+       return *(__force volatile u32 *)addr;
 }
 
-static inline void __raw_writeb(u8 b, unsigned long addr)
+static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
 {
-       *(volatile u8 *)addr = b;
+       *(__force volatile u8 *)addr = b;
 }
 
-static inline void __raw_writew(u16 w, unsigned long addr)
+static inline void __raw_writew(u16 w, volatile void __iomem *addr)
 {
-       *(volatile u16 *)addr = w;
+       *(__force volatile u16 *)addr = w;
 }
 
-static inline void __raw_writel(u32 l, unsigned long addr)
+static inline void __raw_writel(u32 l, volatile void __iomem *addr)
 {
-       *(volatile u32 *)addr = l;
+       *(__force volatile u32 *)addr = l;
 }
 
-static inline u8 __readb(unsigned long addr)
+static inline u8 __readb(const volatile void __iomem *addr)
 {
-       return *(volatile u8 *)addr;
+       return *(__force volatile u8 *)addr;
 }
 
-static inline u16 __readw(unsigned long addr)
+static inline u16 __readw(const volatile void __iomem *addr)
 {
-       return flip_word(*(volatile u16 *)addr);
+       return flip_word(*(__force volatile u16 *)addr);
 }
 
-static inline u32 __readl(unsigned long addr)
+static inline u32 __readl(const volatile void __iomem *addr)
 {
-       return flip_dword(*(volatile u32 *)addr);
+       return flip_dword(*(__force volatile u32 *)addr);
 }
 
-static inline void __writeb(u8 b, unsigned long addr)
+static inline void __writeb(u8 b, volatile void __iomem *addr)
 {
-       *(volatile u8 *)addr = b;
+       *(__force volatile u8 *)addr = b;
 }
 
-static inline void __writew(u16 w, unsigned long addr)
+static inline void __writew(u16 w, volatile void __iomem *addr)
 {
-       *(volatile u16 *)addr = flip_word(w);
+       *(__force volatile u16 *)addr = flip_word(w);
 }
 
-static inline void __writel(u32 l, unsigned long addr)
+static inline void __writel(u32 l, volatile void __iomem *addr)
 {
-       *(volatile u32 *)addr = flip_dword(l);
+       *(__force volatile u32 *)addr = flip_dword(l);
 }
 
-#define readb(__addr)          __readb((unsigned long)(__addr))
-#define readw(__addr)          __readw((unsigned long)(__addr))
-#define readl(__addr)          __readl((unsigned long)(__addr))
+#define readb(__addr)          __readb(__addr)
+#define readw(__addr)          __readw(__addr)
+#define readl(__addr)          __readl(__addr)
 #define readb_relaxed(__addr)  readb(__addr)
 #define readw_relaxed(__addr)  readw(__addr)
 #define readl_relaxed(__addr)  readl(__addr)
 
-#define writeb(__b, __addr)    __writeb((__b),(unsigned long)(__addr))
-#define writew(__w, __addr)    __writew((__w),(unsigned long)(__addr))
-#define writel(__l, __addr)    __writel((__l),(unsigned long)(__addr))
+#define writeb(__b, __addr)    __writeb((__b),(__addr))
+#define writew(__w, __addr)    __writew((__w),(__addr))
+#define writel(__l, __addr)    __writel((__l),(__addr))
 
 /*
  * I/O space operations
@@ -124,15 +117,15 @@ static inline void __writel(u32 l, unsigned long addr)
  * mapped somewhere into virtual kernel space and we
  * can use inb/outb again.
  */
-#define inb_local(__addr)      __readb((unsigned long)(__addr))
-#define inb(__addr)            __readb((unsigned long)(__addr))
-#define inw(__addr)            __readw((unsigned long)(__addr))
-#define inl(__addr)            __readl((unsigned long)(__addr))
+#define inb_local(__addr)      __readb((void __iomem *)(unsigned long)(__addr))
+#define inb(__addr)            __readb((void __iomem *)(unsigned long)(__addr))
+#define inw(__addr)            __readw((void __iomem *)(unsigned long)(__addr))
+#define inl(__addr)            __readl((void __iomem *)(unsigned long)(__addr))
 
-#define outb_local(__b, __addr)        __writeb(__b, (unsigned long)(__addr))
-#define outb(__b, __addr)      __writeb(__b, (unsigned long)(__addr))
-#define outw(__w, __addr)      __writew(__w, (unsigned long)(__addr))
-#define outl(__l, __addr)      __writel(__l, (unsigned long)(__addr))
+#define outb_local(__b, __addr)        __writeb(__b, (void __iomem *)(unsigned long)(__addr))
+#define outb(__b, __addr)      __writeb(__b, (void __iomem *)(unsigned long)(__addr))
+#define outw(__w, __addr)      __writew(__w, (void __iomem *)(unsigned long)(__addr))
+#define outl(__l, __addr)      __writel(__l, (void __iomem *)(unsigned long)(__addr))
 
 #define inb_p(__addr)          inb(__addr)
 #define outb_p(__b, __addr)    outb(__b, __addr)
@@ -156,73 +149,112 @@ extern void insl(unsigned long addr, void *dst, unsigned long count);
  * SBus has only one, memory mapped, I/O space.
  * We do not need to flip bytes for SBus of course.
  */
-static inline u8 _sbus_readb(unsigned long addr)
+static inline u8 _sbus_readb(const volatile void __iomem *addr)
 {
-       return *(volatile u8 *)addr;
+       return *(__force volatile u8 *)addr;
 }
 
-static inline u16 _sbus_readw(unsigned long addr)
+static inline u16 _sbus_readw(const volatile void __iomem *addr)
 {
-       return *(volatile u16 *)addr;
+       return *(__force volatile u16 *)addr;
 }
 
-static inline u32 _sbus_readl(unsigned long addr)
+static inline u32 _sbus_readl(const volatile void __iomem *addr)
 {
-       return *(volatile u32 *)addr;
+       return *(__force volatile u32 *)addr;
 }
 
-static inline void _sbus_writeb(u8 b, unsigned long addr)
+static inline void _sbus_writeb(u8 b, volatile void __iomem *addr)
 {
-       *(volatile u8 *)addr = b;
+       *(__force volatile u8 *)addr = b;
 }
 
-static inline void _sbus_writew(u16 w, unsigned long addr)
+static inline void _sbus_writew(u16 w, volatile void __iomem *addr)
 {
-       *(volatile u16 *)addr = w;
+       *(__force volatile u16 *)addr = w;
 }
 
-static inline void _sbus_writel(u32 l, unsigned long addr)
+static inline void _sbus_writel(u32 l, volatile void __iomem *addr)
 {
-       *(volatile u32 *)addr = l;
+       *(__force volatile u32 *)addr = l;
 }
 
 /*
  * The only reason for #define's is to hide casts to unsigned long.
  */
-#define sbus_readb(__addr)             _sbus_readb((unsigned long)(__addr))
-#define sbus_readw(__addr)             _sbus_readw((unsigned long)(__addr))
-#define sbus_readl(__addr)             _sbus_readl((unsigned long)(__addr))
-#define sbus_writeb(__b, __addr)       _sbus_writeb(__b, (unsigned long)(__addr))
-#define sbus_writew(__w, __addr)       _sbus_writew(__w, (unsigned long)(__addr))
-#define sbus_writel(__l, __addr)       _sbus_writel(__l, (unsigned long)(__addr))
+#define sbus_readb(__addr)             _sbus_readb(__addr)
+#define sbus_readw(__addr)             _sbus_readw(__addr)
+#define sbus_readl(__addr)             _sbus_readl(__addr)
+#define sbus_writeb(__b, __addr)       _sbus_writeb(__b, __addr)
+#define sbus_writew(__w, __addr)       _sbus_writew(__w, __addr)
+#define sbus_writel(__l, __addr)       _sbus_writel(__l, __addr)
+
+static inline void sbus_memset_io(volatile void __iomem *__dst, int c, __kernel_size_t n)
+{
+       while(n--) {
+               sbus_writeb(c, __dst);
+               __dst++;
+       }
+}
 
-static inline void *sbus_memset_io(void *__dst, int c, __kernel_size_t n)
+static inline void
+_memset_io(volatile void __iomem *dst, int c, __kernel_size_t n)
 {
-       unsigned long dst = (unsigned long)__dst;
+       volatile void __iomem *d = dst;
 
-       while(n--) {
-               sbus_writeb(c, dst);
-               dst++;
+       while (n--) {
+               writeb(c, d);
+               d++;
+       }
+}
+
+#define memset_io(d,c,sz)      _memset_io(d,c,sz)
+
+static inline void
+_memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n)
+{
+       char *d = dst;
+
+       while (n--) {
+               char tmp = readb(src);
+               *d++ = tmp;
+               src++;
+       }
+}
+
+#define memcpy_fromio(d,s,sz)  _memcpy_fromio(d,s,sz)
+
+static inline void 
+_memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n)
+{
+       const char *s = src;
+       volatile void __iomem *d = dst;
+
+       while (n--) {
+               char tmp = *s++;
+               writeb(tmp, d);
+               d++;
        }
-       return (void *) dst;
 }
 
+#define memcpy_toio(d,s,sz)    _memcpy_toio(d,s,sz)
+
 #ifdef __KERNEL__
 
 /*
  * Bus number may be embedded in the higher bits of the physical address.
  * This is why we have no bus number argument to ioremap().
  */
-extern void *ioremap(unsigned long offset, unsigned long size);
+extern void __iomem *ioremap(unsigned long offset, unsigned long size);
 #define ioremap_nocache(X,Y)   ioremap((X),(Y))
-extern void iounmap(void *addr);
+extern void iounmap(volatile void __iomem *addr);
 
 /*
  * Bus number may be in res->flags... somewhere.
  */
-extern unsigned long sbus_ioremap(struct resource *res, unsigned long offset,
+extern void __iomem *sbus_ioremap(struct resource *res, unsigned long offset,
     unsigned long size, char *name);
-extern void sbus_iounmap(unsigned long vaddr, unsigned long size);
+extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
 
 
 /*
index be60a9a..c6022a5 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <asm/idprom.h>
+#include <asm/io.h>
 
 /*       M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
  *
@@ -38,8 +39,8 @@
  * other than the control register are in binary coded decimal. Some
  * control bits also live outside the control register.
  */
-#define mostek_read(_addr)             (*((volatile u8 *)(_addr)))
-#define mostek_write(_addr,_val)       ((*((volatile u8 *)(_addr))) = (_val))
+#define mostek_read(_addr)             readb(_addr)
+#define mostek_write(_addr,_val)       writeb(_val, _addr)
 #define MOSTEK_EEPROM          0x0000UL
 #define MOSTEK_IDPROM          0x07d8UL
 #define MOSTEK_CREG            0x07f8UL
@@ -65,7 +66,7 @@ struct mostek48t02 {
 };
 
 extern spinlock_t mostek_lock;
-extern unsigned long mstk48t02_regs;
+extern void __iomem *mstk48t02_regs;
 
 /* Control register values. */
 #define        MSTK_CREG_WRITE 0x80    /* Must set this before placing values. */
index 86dc000..7fa2c7d 100644 (file)
@@ -4,7 +4,6 @@
 
 #ifdef __KERNEL__
 #include <asm/ptrace.h>
-#endif
 
 #ifndef __ASSEMBLY__
 
@@ -59,4 +58,6 @@ typedef struct {
 
 #endif /* !(__ASSEMBLY__) */
 
+#endif /* (__KERNEL__) */
+
 #endif /* !(__SPARC_SIGCONTEXT_H) */
index 4b62878..870a3b3 100644 (file)
@@ -7,10 +7,6 @@
 #define _ASMsparc_TIMEX_H
 
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
-#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)
 
 /* XXX Maybe do something better at some point... -DaveM */
 typedef unsigned long cycles_t;
index e7890f0..cc98a73 100644 (file)
 
 #define ENOMEDIUM       125     /* No medium found */
 #define EMEDIUMTYPE     126     /* Wrong medium type */
+#define        ECANCELED       127     /* Operation Cancelled */
+#define        ENOKEY          128     /* Required key not available */
+#define        EKEYEXPIRED     129     /* Key has expired */
+#define        EKEYREVOKED     130     /* Key has been revoked */
+#define        EKEYREJECTED    131     /* Key was rejected by service */
 
 #endif /* !(_SPARC64_ERRNO_H) */
index 42b4cc6..1706251 100644 (file)
@@ -10,6 +10,12 @@ typedef u32 kprobe_opcode_t;
 #define BREAKPOINT_INSTRUCTION_2 0x91d02071 /* ta 0x71 */
 #define MAX_INSN_SIZE 2
 
+/* Architecture specific copy of original instruction*/
+struct arch_specific_insn {
+       /* copy of the original instruction */
+       kprobe_opcode_t insn[MAX_INSN_SIZE];
+};
+
 #ifdef CONFIG_KPROBES
 extern int kprobe_exceptions_notify(struct notifier_block *self,
                                    unsigned long val, void *data);
index 904100a..9e8d417 100644 (file)
@@ -9,10 +9,6 @@
 #include <asm/timer.h>
 
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
-#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)
 
 /* Getting on the cycle counter on sparc64. */
 typedef unsigned long cycles_t;
index 5e297ac..b683f10 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef __UM_ATOMIC_H
 #define __UM_ATOMIC_H
 
+/* The i386 atomic.h calls printk, but doesn't include kernel.h, so we
+ * include it here.
+ */
+#include "linux/kernel.h"
+
 #include "asm/arch/atomic.h"
 
 #endif
index da49d29..1224b26 100644 (file)
@@ -1,6 +1,26 @@
-#ifndef __UM_HARDIRQ_H
-#define __UM_HARDIRQ_H
+/* (c) 2004 cw@f00f.org, GPLv2 blah blah */
 
-#include "asm/arch/hardirq.h"
+#ifndef __ASM_UM_HARDIRQ_H
+#define __ASM_UM_HARDIRQ_H
 
-#endif
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+/* NOTE: When SMP works again we might want to make this
+ * ____cacheline_aligned or maybe use per_cpu state? --cw */
+typedef struct {
+       unsigned int __softirq_pending;
+} irq_cpustat_t;
+
+#include <linux/irq_cpustat.h>
+
+/* As this would be very strange for UML to get we BUG() after the
+ * printk. */
+static inline void ack_bad_irq(unsigned int irq)
+{
+       printk(KERN_ERR "unexpected IRQ %02x\n", irq);
+       BUG();
+}
+
+#endif /* __ASM_UM_HARDIRQ_H */
index 8c472eb..a1bb25f 100644 (file)
@@ -10,8 +10,6 @@
 
 #include "linux/config.h"
 
-#include "asm/current.h"
-
 #define pt_regs pt_regs_subarch
 #define show_regs show_regs_subarch
 
index 7493d6d..974fc08 100644 (file)
@@ -13,29 +13,8 @@ typedef struct {
 
 #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
- * HARDIRQ_MASK: 0x0000ff00
- * SOFTIRQ_MASK: 0x00ff0000
- */
-
-#define PREEMPT_BITS   8
-#define SOFTIRQ_BITS   8
 #define HARDIRQ_BITS   8
 
-#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
index 255f48b..ad9d607 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * include/asm-v850/io.h -- Misc I/O operations
  *
- *  Copyright (C) 2001,02,03  NEC Electronics Corporation
- *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2001,02,03,04  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03,04  Miles Bader <miles@gnu.org>
  *
  * 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
@@ -102,6 +102,8 @@ outsl (unsigned long port, const void *src, unsigned long count)
 #define ioremap_writethrough(physaddr, size)   (physaddr)
 #define ioremap_fullcache(physaddr, size)      (physaddr)
 
+#define mmiowb()
+
 #define page_to_phys(page)      ((page - mem_map) << PAGE_SHIFT)
 #if 0
 /* This is really stupid; don't define it.  */
@@ -114,4 +116,7 @@ outsl (unsigned long port, const void *src, unsigned long count)
 #define phys_to_virt(addr)     ((void *)__phys_to_virt (addr))
 #define virt_to_phys(addr)     ((unsigned long)__virt_to_phys (addr))
 
+#define memcpy_fromio(dst, src, len) memcpy (dst, (void *)src, len)
+#define memcpy_toio(dst, src, len) memcpy ((void *)dst, src, len)
+
 #endif /* __V850_IO_H__ */
index 865c87c..ccb7297 100644 (file)
@@ -54,7 +54,9 @@ typedef struct {
 
 #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
 
-#include <asm/bitops.h>
+/* We used to include <asm/bitops.h> here, which seems the right thing, but
+   it caused nasty include-file definition order problems.  Removing the
+   include seems to work, so fingers crossed...  */
 
 #undef __FD_SET
 #define __FD_SET(fd, fd_set) \
index 729e278..6279e5a 100644 (file)
@@ -7,10 +7,6 @@
 #define __V850_TIMEX_H__
 
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
-#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)
 
 typedef unsigned long cycles_t;
 
index 62ccf88..c025cc3 100644 (file)
@@ -97,6 +97,7 @@ extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
 extern int APIC_init_uniprocessor (void);
 extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
+extern void clustered_apic_check(void);
 
 extern int check_nmi_watchdog(void);
 extern void nmi_watchdog_default(void);
@@ -111,7 +112,6 @@ extern unsigned int nmi_watchdog;
 
 #endif /* CONFIG_X86_LOCAL_APIC */
 
-#define clustered_apic_mode 0
 #define esr_disable 0
 extern unsigned boot_cpu_id;
 
index 8a1025f..183250b 100644 (file)
@@ -45,6 +45,7 @@
 /* Don't duplicate feature flags which are redundant with Intel! */
 #define X86_FEATURE_SYSCALL    (1*32+11) /* SYSCALL/SYSRET */
 #define X86_FEATURE_MMXEXT     (1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_FXSR_OPT   (1*32+25) /* FXSR optimizations */
 #define X86_FEATURE_LM         (1*32+29) /* Long Mode (x86-64) */
 #define X86_FEATURE_3DNOWEXT   (1*32+30) /* AMD 3DNow! extensions */
 #define X86_FEATURE_3DNOW      (1*32+31) /* 3DNow! */
@@ -73,7 +74,8 @@
 #define X86_FEATURE_XTPR       (4*32+14) /* Send Task Priority Messages */
 
 /* More extended AMD flags: CPUID level 0x80000001, ecx, word 5 */
-#define X86_FEATURE_HTVALID    (5*32+ 0) /* HyperThreading valid, otherwise CMP */
+#define X86_FEATURE_LAHF_LM    (5*32+ 0) /* LAHF/SAHF in long mode */
+#define X86_FEATURE_HTVALID    (5*32+ 1) /* HyperThreading valid, otherwise CMP */
 
 #define cpu_has(c, bit)                test_bit(bit, (c)->x86_capability)
 #define boot_cpu_has(bit)      test_bit(bit, boot_cpu_data.x86_capability)
index 004888f..6aefb9c 100644 (file)
@@ -210,6 +210,8 @@ static inline void load_LDT(mm_context_t *pc)
        put_cpu();
 }
 
+extern struct desc_ptr idt_descr;
+
 #endif /* !__ASSEMBLY__ */
 
 #endif
index 9839b92..cfeec4e 100644 (file)
@@ -143,6 +143,11 @@ typedef struct user_i387_struct elf_fpregset_t;
 #ifdef __KERNEL__
 extern void set_personality_64bit(void);
 #define SET_PERSONALITY(ex, ibcs2) set_personality_64bit()
+/*
+ * An executable for which elf_read_implies_exec() returns TRUE will
+ * have the READ_IMPLIES_EXEC personality flag set automatically.
+ */
+#define elf_read_implies_exec(ex, have_pt_gnu_stack)   (!(have_pt_gnu_stack))
        
 /*
  * An executable for which elf_read_implies_exec() returns TRUE will
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
index 9ce1a78..23b3be2 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/threads.h>
 #include <linux/irq.h>
 #include <asm/pda.h>
+#include <asm/apic.h>
 
 #define __ARCH_IRQ_STAT 1
 
 #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
- * HARDIRQ_MASK: 0x0000ff00
- * SOFTIRQ_MASK: 0x00ff0000
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves.
  */
-
-#define PREEMPT_BITS   8
-#define SOFTIRQ_BITS   8
-#define HARDIRQ_BITS   8
-
-#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!
+static inline void ack_bad_irq(unsigned int irq)
+{
+#ifdef CONFIG_X86
+       printk("unexpected IRQ trap at vector %02x\n", irq);
+#ifdef CONFIG_X86_LOCAL_APIC
+       /*
+        * Currently unexpected vectors happen only on SMP and APIC.
+        * We _must_ ack these because every local APIC has only N
+        * irq slots per priority level, and a 'hanging, unacked' IRQ
+        * holds up an irq slot - in excessive cases (when multiple
+        * unexpected vectors occur) that might lock up the APIC
+        * completely.
+        */
+       ack_APIC_irq();
 #endif
-
-#define nmi_enter()            (irq_enter())
-#define nmi_exit()             (preempt_count() -= HARDIRQ_OFFSET)
-
-#define irq_enter()            (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
+}
 #endif /* __ASM_HARDIRQ_H */
index 08ee1e7..a3877f5 100644 (file)
 #define HPET_ID_LEGSUP 0x00008000
 #define HPET_ID_NUMBER 0x00001f00
 #define HPET_ID_REV    0x000000ff
+#define        HPET_ID_NUMBER_SHIFT    8
 
 #define HPET_ID_VENDOR_SHIFT   16
 #define HPET_ID_VENDOR_8086    0x8086
 
 #define HPET_CFG_ENABLE        0x001
 #define HPET_CFG_LEGACY        0x002
+#define        HPET_LEGACY_8254        2
+#define        HPET_LEGACY_RTC         8
 
 #define HPET_TN_ENABLE         0x004
 #define HPET_TN_PERIODIC       0x008
@@ -43,6 +46,7 @@
 
 extern int is_hpet_enabled(void);
 extern int hpet_rtc_timer_init(void);
+extern int oem_force_hpet_timer(void);
 
 #ifdef CONFIG_HPET_EMULATE_RTC
 extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
index 2882961..7efc932 100644 (file)
@@ -199,7 +199,7 @@ extern int skip_ioapic_setup;
  * If we use the IO-APIC for IRQ routing, disable automatic
  * assignment of PCI IRQ's.
  */
-#define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup)
+#define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs)
 
 #ifdef CONFIG_ACPI_BOOT
 extern int io_apic_get_unique_id (int ioapic, int apic_id);
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 */
index f0de267..6277f75 100644 (file)
@@ -16,8 +16,8 @@ struct die_args {
 /* Note - you should never unregister because that can race with NMIs.
    If you really want to do it first unregister - then synchronize_kernel - then free. 
   */
+int register_die_notifier(struct notifier_block *nb);
 extern struct notifier_block *die_chain;
-
 /* Grossly misnamed. */
 enum die_val { 
        DIE_OOPS = 1,
@@ -32,6 +32,7 @@ enum die_val {
        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)
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 */
index df002c5..21d56b0 100644 (file)
@@ -47,5 +47,11 @@ static inline void unset_nmi_pm_callback(struct pm_dev * dev)
 #endif /* CONFIG_PM */
  
 extern void default_do_nmi(struct pt_regs *);
+extern void die_nmi(char *str, struct pt_regs *regs);
+
+#define get_nmi_reason() inb(0x61)
+
+extern int panic_on_timeout;
+extern int unknown_nmi_panic;
  
 #endif /* ASM_NMI_H */
index 9962665..e3ee503 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ASM_X8664_NUMA_H 
 #define _ASM_X8664_NUMA_H 1
 
+#include <linux/nodemask.h>
+
 #define MAXNODE 8 
 #define NODEMASK 0xff
 
index f222306..7f85def 100644 (file)
@@ -12,6 +12,8 @@ extern void get_cpu_vendor(struct cpuinfo_x86*);
 extern void start_kernel(void);
 extern void pda_init(int); 
 
+extern void early_idt_handler(void);
+
 extern void mcheck_init(struct cpuinfo_x86 *c);
 extern void init_memory_mapping(void);
 
index c25270a..3629306 100644 (file)
@@ -26,6 +26,10 @@ extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg,
 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);
+extern void *swiotlb_alloc_coherent (struct device *hwdev, size_t size,
+                                    dma_addr_t *dma_handle, int flags);
+extern void swiotlb_free_coherent (struct device *hwdev, size_t size,
+                                  void *vaddr, dma_addr_t dma_handle);
 
 #ifdef CONFIG_SWIOTLB
 extern int swiotlb;
index 6671eb6..55ac71f 100644 (file)
@@ -123,7 +123,7 @@ struct alt_instr {
  * If you use variable sized constraints like "m" or "g" in the 
  * replacement maake sure to pad to the worst case length.
  */
-#define alternative_input(oldinstr, newinstr, feature, input)          \
+#define alternative_input(oldinstr, newinstr, feature, input...)       \
        asm volatile ("661:\n\t" oldinstr "\n662:\n"                    \
                      ".section .altinstructions,\"a\"\n"               \
                      "  .align 8\n"                                    \
@@ -135,7 +135,7 @@ struct alt_instr {
                      ".previous\n"                                     \
                      ".section .altinstr_replacement,\"ax\"\n"         \
                      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
-                     ".previous" :: "i" (feature), input)
+                     ".previous" :: "i" (feature), ##input)
 
 /*
  * Clear and set 'TS' bit respectively
index 73e4fa1..4e27434 100644 (file)
@@ -125,7 +125,7 @@ static inline struct thread_info *stack_thread_info(void)
 /* work to do on any return to user space */
 #define _TIF_ALLWORK_MASK 0x0000FFFF   
 
-#define PREEMPT_ACTIVE     0x4000000
+#define PREEMPT_ACTIVE     0x10000000
 
 /*
  * Thread-synchronous status.
index b78e931..b0c8d43 100644 (file)
@@ -21,7 +21,7 @@ enum vsyscall_num {
 #define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16)))
 #define __section_sysctl_vsyscall __attribute__ ((unused, __section__ (".sysctl_vsyscall"), aligned(16)))
 #define __section_xtime __attribute__ ((unused, __section__ (".xtime"), aligned(16)))
-#define __section_xtime_lock __attribute__ ((unused, __section__ (".xtime_lock"), aligned(L1_CACHE_BYTES)))
+#define __section_xtime_lock __attribute__ ((unused, __section__ (".xtime_lock"), aligned(16)))
 
 #define VXTIME_TSC     1
 #define VXTIME_HPET    2
@@ -36,8 +36,8 @@ struct vxtime_data {
        int mode;
 };
 
-#define hpet_readl(a)           readl(fix_to_virt(FIX_HPET_BASE) + a)
-#define hpet_writel(d,a)        writel(d, fix_to_virt(FIX_HPET_BASE) + a)
+#define hpet_readl(a)           readl((void *)fix_to_virt(FIX_HPET_BASE) + a)
+#define hpet_writel(d,a)        writel(d, (void *)fix_to_virt(FIX_HPET_BASE) + a)
 
 /* vsyscall space (readonly) */
 extern struct vxtime_data __vxtime;
index 4df1c54..aa71583 100644 (file)
 #define ATMSIGD_CTRL _IO('a',ATMIOC_SPECIAL)
                                /* become ATM signaling demon control socket */
 
-enum atmsvc_msg_type { as_catch_null,as_bind,as_connect,as_accept,as_reject,
-  as_listen,as_okay,as_error,as_indicate,as_close,as_itf_notify,
-  as_modify,as_identify,as_terminate };
+enum atmsvc_msg_type { as_catch_null, as_bind, as_connect, as_accept, as_reject,
+                      as_listen, as_okay, as_error, as_indicate, as_close,
+                      as_itf_notify, as_modify, as_identify, as_terminate,
+                      as_addparty, as_dropparty };
 
 struct atmsvc_msg {
        enum atmsvc_msg_type type;
index 053d6e4..bcb0b1e 100644 (file)
@@ -42,7 +42,7 @@ static inline int generic_ffs(int x)
  * fls: find last bit set.
  */
 
-extern __inline__ int generic_fls(int x)
+static __inline__ int generic_fls(int x)
 {
        int r = 32;
 
@@ -71,7 +71,7 @@ extern __inline__ int generic_fls(int x)
        return r;
 }
 
-extern __inline__ int get_bitmask_order(unsigned int count)
+static __inline__ int get_bitmask_order(unsigned int count)
 {
        int order;
        
index 40d40b4..bef8789 100644 (file)
 #define __constant_be32_to_cpu(x) ((__force __u32)(__be32)(x))
 #define __constant_cpu_to_be16(x) ((__force __be16)(__u16)(x))
 #define __constant_be16_to_cpu(x) ((__force __u16)(__be16)(x))
-#define __cpu_to_le64(x) ((__force __le64)___swab64((x)))
-#define __le64_to_cpu(x) ___swab64((__force __u64)(__le64)(x))
-#define __cpu_to_le32(x) ((__force __le32)___swab32((x)))
-#define __le32_to_cpu(x) ___swab32((__force __u32)(__le32)(x))
-#define __cpu_to_le16(x) ((__force __le16)___swab16((x)))
-#define __le16_to_cpu(x) ___swab16((__force __u16)(__le16)(x))
+#define __cpu_to_le64(x) ((__force __le64)__swab64((x)))
+#define __le64_to_cpu(x) __swab64((__force __u64)(__le64)(x))
+#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
+#define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x))
+#define __cpu_to_le16(x) ((__force __le16)__swab16((x)))
+#define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x))
 #define __cpu_to_be64(x) ((__force __be64)(__u64)(x))
 #define __be64_to_cpu(x) ((__force __u64)(__be64)(x))
 #define __cpu_to_be32(x) ((__force __be32)(__u32)(x))
index c05349b..86e62b7 100644 (file)
 #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
 #define __cpu_to_le16(x) ((__force __le16)(__u16)(x))
 #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
-#define __cpu_to_be64(x) ((__force __be64)___swab64((x)))
-#define __be64_to_cpu(x) ___swab64((__force __u64)(__be64)(x))
-#define __cpu_to_be32(x) ((__force __be32)___swab32((x)))
-#define __be32_to_cpu(x) ___swab32((__force __u32)(__be32)(x))
-#define __cpu_to_be16(x) ((__force __be16)___swab16((x)))
-#define __be16_to_cpu(x) ___swab16((__force __u16)(__be16)(x))
+#define __cpu_to_be64(x) ((__force __be64)__swab64((x)))
+#define __be64_to_cpu(x) __swab64((__force __u64)(__be64)(x))
+#define __cpu_to_be32(x) ((__force __be32)__swab32((x)))
+#define __be32_to_cpu(x) __swab32((__force __u32)(__be32)(x))
+#define __cpu_to_be16(x) ((__force __be16)__swab16((x)))
+#define __be16_to_cpu(x) __swab16((__force __u16)(__be16)(x))
 
 static inline __le64 __cpu_to_le64p(const __u64 *p)
 {
index 2aaf05c..04fa7df 100644 (file)
@@ -52,7 +52,7 @@ struct cycx_device {
        char in_isr;                    /* interrupt-in-service flag */
        char buff_int_mode_unbusy;      /* flag for carrying out dev_tint */
        wait_queue_head_t wait_stats;  /* to wait for the STATS indication */
-       void *mbox;                     /* -> mailbox */
+       void __iomem *mbox;                     /* -> mailbox */
        void (*isr)(struct cycx_device* card);  /* interrupt service routine */
        int (*exec)(struct cycx_device* card, void* u_cmd, void* u_data);
        union {
index a71d2dc..6621df8 100644 (file)
 struct cycx_hw {
        u32 fwid;
        int irq;
-       void *dpmbase;
+       void __iomem *dpmbase;
        u32 dpmsize;
        u32 reserved[5];
 };
 
 /* Function Prototypes */
-extern int cycx_setup(struct cycx_hw *hw, void *sfm, u32 len);
+extern int cycx_setup(struct cycx_hw *hw, void *sfm, u32 len, unsigned long base);
 extern int cycx_down(struct cycx_hw *hw);
 extern int cycx_peek(struct cycx_hw *hw, u32 addr, void *buf, u32 len);
 extern int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len);
-extern int cycx_exec(void *addr);
+extern int cycx_exec(void __iomem *addr);
 
 extern void cycx_inten(struct cycx_hw *hw);
 extern void cycx_intr(struct cycx_hw *hw);
index 7abe54e..a6282ab 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2001 Sistina Software (UK) Limited.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the LGPL.
  */
@@ -57,6 +58,8 @@ typedef void (*dm_resume_fn) (struct dm_target *ti);
 typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
                             char *result, unsigned int maxlen);
 
+typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);
+
 void dm_error(const char *message);
 
 /*
@@ -82,6 +85,7 @@ struct target_type {
        dm_suspend_fn suspend;
        dm_resume_fn resume;
        dm_status_fn status;
+       dm_message_fn message;
 };
 
 struct io_restrictions {
index 7516639..fae9395 100644 (file)
@@ -3,11 +3,12 @@
  * The general structure of this is vaguely based on how
  * the Amiga port handles Zorro boards.
  * Copyright (C) Peter Maydell 05/1998 <pmaydell@chiark.greenend.org.uk>
+ * Converted to driver model Jochen Friedrich <jochen@scram.de>
  *
  * The board IDs are from the NetBSD kernel, which for once provided
  * helpful comments...
  *
- * This goes with arch/m68k/hp300/dio.c
+ * This goes with drivers/dio/dio.c
  */
 
 #ifndef _LINUX_DIO_H
  * so currently we just don't handle DIO-II boards.  It wouldn't be hard to 
  * do with ioremap() though.
  */
+
+#include <linux/device.h>
+
 #ifdef __KERNEL__
+
+#include <asm/hp300hw.h>
+
+typedef __u16 dio_id;
+
+    /*
+     *  DIO devices
+     */
+
+struct dio_dev {
+       struct dio_bus *bus;
+       dio_id id;
+       int scode;
+       struct dio_driver *driver;      /* which driver has allocated this device */
+       struct device dev;              /* Generic device interface */
+       u8 ipl;
+       char name[64];
+       struct resource resource;
+};
+
+#define to_dio_dev(n) container_of(n, struct dio_dev, dev)
+
+    /*
+     *  DIO bus
+     */
+
+struct dio_bus {
+       struct list_head devices;           /* list of devices on this bus */
+       unsigned int num_resources;         /* number of resources */
+       struct resource resources[2];       /* address space routed to this bus */
+       struct device dev;
+       char name[10];
+};
+
+extern struct dio_bus dio_bus;      /* Single DIO bus */
+extern struct bus_type dio_bus_type;
+
+    /*
+     *  DIO device IDs
+     */
+
+struct dio_device_id {
+       dio_id id;                    /* Device ID or DIO_WILDCARD */
+       unsigned long driver_data;    /* Data private to the driver */
+};
+
+    /*
+     *  DIO device drivers
+     */
+
+struct dio_driver {
+       struct list_head node;
+       char *name;
+       const struct dio_device_id *id_table;     /* NULL if wants all devices */
+       int (*probe)(struct dio_dev *z, const struct dio_device_id *id);
+/* New device inserted */
+       void (*remove)(struct dio_dev *z);        /* Device removed (NULL if not a hot-plug capable driver) */
+       struct device_driver driver;
+};
+
+#define to_dio_driver(drv)    container_of(drv, struct dio_driver, driver)
+
 /* DIO/DIO-II boards all have the following 8bit registers.
  * These are offsets from the base of the device.
  */
-#define DIO_IDOFF     0x01                        /* primary device ID */
-#define DIO_IPLOFF    0x03                        /* interrupt priority level */
-#define DIO_SECIDOFF  0x15                        /* secondary device ID */
-#define DIOII_SIZEOFF 0x101                       /* device size, DIO-II only */
-
-/* The internal HPIB device is special; this is its physaddr; its select code is 7. 
- * The reason why we have to treat it specially is because apparently it's broken:
- * the device ID isn't consistent/reliable. *sigh*
- */
-#define DIO_IHPIBADDR 0x47800
-#define DIO_IHPIBSCODE 7
-
-/* If we don't have the internal HPIB defined, then treat select code 7 like
- * any other. If we *do* have internal HPIB, then we just have to assume that
- * select code 7 is the internal HPIB regardless of the ID register :-<
- */
-#define CONFIG_IHPIB /* hack hack : not yet a proper config option */
-#ifdef CONFIG_IHPIB
-#define DIO_ISIHPIB(scode) ((scode) == DIO_IHPIBSCODE)
-#else
-#define DIO_ISIHPIB(scode) 0
-#endif
-
-#define DIO_VIRADDRBASE 0xf0000000                /* vir addr where IOspace is mapped */
+#define DIO_IDOFF     0x01             /* primary device ID */
+#define DIO_IPLOFF    0x03             /* interrupt priority level */
+#define DIO_SECIDOFF  0x15             /* secondary device ID */
+#define DIOII_SIZEOFF 0x101            /* device size, DIO-II only */
+#define DIO_VIRADDRBASE 0xf0000000UL   /* vir addr where IOspace is mapped */
 
 #define DIO_BASE                0x600000        /* start of DIO space */
 #define DIO_END                 0x1000000       /* end of DIO space */
 /* Highest valid select code. If we add DIO-II support this should become
  * 256 for everything except HP320, which only has DIO.
  */
-#define DIO_SCMAX 32                             
+#define DIO_SCMAX (hp300_model == HP_320 ? 32 : 256)
 #define DIOII_SCBASE 132 /* lowest DIO-II select code */
 #define DIO_SCINHOLE(scode) (((scode) >= 32) && ((scode) < DIOII_SCBASE))
+#define DIO_ISDIOII(scode) ((scode) >= 132 && (scode) < 256)
 
 /* macros to read device IDs, given base address */
 #define DIO_ID(baseaddr) in_8((baseaddr) + DIO_IDOFF)
  * In practice this is only important for framebuffers,
  * and everybody else just sets ID fields equal to the DIO_ID_FOO value.
  */
-#define DIO_ENCODE_ID(pr,sec) ((((int)sec & 0xff) << 8) & ((int)pr & 0xff))
+#define DIO_ENCODE_ID(pr,sec) ((((int)sec & 0xff) << 8) | ((int)pr & 0xff))
 /* macro to determine whether a given primary ID requires a secondary ID byte */
 #define DIO_NEEDSSECID(id) ((id) == DIO_ID_FBUFFER)
+#define DIO_WILDCARD 0xff
 
 /* Now a whole slew of macros giving device IDs and descriptive strings: */
 #define DIO_ID_DCA0     0x02 /* 98644A serial */
 #define DIO_DESC_LAN "98643A LANCE ethernet"
 #define DIO_ID_FHPIB    0x08 /* 98625A/98625B fast HP-IB */
 #define DIO_DESC_FHPIB "98625A/98625B fast HPIB"
-#define DIO_ID_NHPIB    0x80 /* 98624A HP-IB (normal ie slow) */
+#define DIO_ID_NHPIB    0x01 /* 98624A HP-IB (normal ie slow) */
 #define DIO_DESC_NHPIB "98624A HPIB"
-#define DIO_ID_IHPIB    0x00 /* internal HPIB (not its real ID, it hasn't got one! */
-#define DIO_DESC_IHPIB "internal HPIB"
-#define DIO_ID_SCSI0    0x07 /* 98625A SCSI */
-#define DIO_DESC_SCSI0 "98625A SCSI0"
+#define DIO_ID_SCSI0    0x07 /* 98265A SCSI */
+#define DIO_DESC_SCSI0 "98265A SCSI0"
 #define DIO_ID_SCSI1    0x27 /* ditto */
-#define DIO_DESC_SCSI1 "98625A SCSI1"
+#define DIO_DESC_SCSI1 "98265A SCSI1"
 #define DIO_ID_SCSI2    0x47 /* ditto */
-#define DIO_DESC_SCSI2 "98625A SCSI2"
+#define DIO_DESC_SCSI2 "98265A SCSI2"
 #define DIO_ID_SCSI3    0x67 /* ditto */
-#define DIO_DESC_SCSI3 "98625A SCSI3"
+#define DIO_DESC_SCSI3 "98265A SCSI3"
 #define DIO_ID_FBUFFER  0x39 /* framebuffer: flavour is distinguished by secondary ID */
 #define DIO_DESC_FBUFFER "bitmapped display"
 /* the NetBSD kernel source is a bit unsure as to what these next IDs actually do :-> */
  */
 
 extern int dio_find(int deviceid);
-extern void *dio_scodetoviraddr(int scode);
-extern int dio_scodetoipl(int scode);
-extern const char *dio_scodetoname(int scode);
-extern void dio_config_board(int scode);
-extern void dio_unconfig_board(int scode);
+extern unsigned long dio_scodetophysaddr(int scode);
+extern void dio_create_sysfs_dev_files(struct dio_dev *);
+
+/* New-style probing */
+extern int dio_register_driver(struct dio_driver *);
+extern void dio_unregister_driver(struct dio_driver *);
+extern const struct dio_device_id *dio_match_device(const struct dio_device_id *ids, const struct dio_dev *z);
+static inline struct dio_driver *dio_dev_driver(const struct dio_dev *d)
+{
+    return d->driver;
+}
+
+#define dio_resource_start(d) ((d)->resource.start)
+#define dio_resource_end(d)   ((d)->resource.end)
+#define dio_resource_len(d)   ((d)->resource.end-(d)->resource.start+1)
+#define dio_resource_flags(d) ((d)->resource.flags)
+
+#define dio_request_device(d, name) \
+    request_mem_region(dio_resource_start(d), dio_resource_len(d), name)
+#define dio_release_device(d) \
+    release_mem_region(dio_resource_start(d), dio_resource_len(d))
+
+/* Similar to the helpers above, these manipulate per-dio_dev
+ * driver-specific data.  They are really just a wrapper around
+ * the generic device structure functions of these calls.
+ */
+static inline void *dio_get_drvdata (struct dio_dev *d)
+{
+       return dev_get_drvdata(&d->dev);
+}
+
+static inline void dio_set_drvdata (struct dio_dev *d, void *data)
+{
+       dev_set_drvdata(&d->dev, data);
+}
+
+/*
+ * A helper function which helps ensure correct dio_driver
+ * setup and cleanup for commonly-encountered hotplug/modular cases
+ *
+ * This MUST stay in a header, as it checks for -DMODULE
+ */
+static inline int dio_module_init(struct dio_driver *drv)
+{
+       int rc = dio_register_driver(drv);
+
+       if (rc > 0)
+               return 0;
+
+       /* iff CONFIG_HOTPLUG and built into kernel, we should
+        * leave the driver around for future hotplug events.
+        * For the module case, a hotplug daemon of some sort
+        * should load a module in response to an insert event. */
+#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
+       if (rc == 0)
+               return 0;
+#else
+       if (rc == 0)
+               rc = -ENODEV;
+#endif
+
+       /* if we get here, we need to clean up DIO driver instance
+        * and return some sort of error */
+       dio_unregister_driver(drv);
 
+       return rc;
+}
 
 #endif /* __KERNEL__ */
 #endif /* ndef _LINUX_DIO_H */
index e11c909..6919b09 100644 (file)
@@ -109,6 +109,8 @@ struct divert_cf
 #include <linux/skbuff.h>
 
 #ifdef CONFIG_NET_DIVERT
+#include <linux/netdevice.h>
+
 int alloc_divert_blk(struct net_device *);
 void free_divert_blk(struct net_device *);
 int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg);
index 03f99db..183e777 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the LGPL.
  */
@@ -76,6 +77,9 @@
  *
  * DM_TABLE_STATUS:
  * Return the targets status for the 'active' table.
+ *
+ * DM_TARGET_MSG:
+ * Pass a message string to the target at a specific offset of a device.
  */
 
 /*
@@ -178,6 +182,15 @@ struct dm_target_versions {
         char name[0];
 };
 
+/*
+ * Used to pass message to a target
+ */
+struct dm_target_msg {
+       uint64_t sector;        /* Device sector */
+
+       char message[0];
+};
+
 /*
  * If you change this make sure you make the corresponding change
  * to dm-ioctl.c:lookup_ioctl()
@@ -204,6 +217,7 @@ enum {
 
        /* Added later */
        DM_LIST_VERSIONS_CMD,
+       DM_TARGET_MSG_CMD,
 };
 
 /*
@@ -232,6 +246,7 @@ typedef char ioctl_struct[308];
 #define DM_TABLE_DEPS_32    _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, ioctl_struct)
 #define DM_TABLE_STATUS_32  _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, ioctl_struct)
 #define DM_LIST_VERSIONS_32 _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, ioctl_struct)
+#define DM_TARGET_MSG_32    _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, ioctl_struct)
 #endif
 
 #define DM_IOCTL 0xfd
@@ -254,10 +269,12 @@ typedef char ioctl_struct[308];
 
 #define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl)
 
+#define DM_TARGET_MSG   _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl)
+
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       1
+#define DM_VERSION_MINOR       3
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2003-12-10)"
+#define DM_VERSION_EXTRA       "-ioctl (2004-09-30)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
index 5cffeed..f134a01 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef _LINUX_DNOTIFY_H
+#define _LINUX_DNOTIFY_H
 /*
  * Directory notification for Linux
  *
 
 struct dnotify_struct {
        struct dnotify_struct * dn_next;
-       unsigned long           dn_mask;        /* Events to be notified
-                                                  see linux/fcntl.h */
+       unsigned long           dn_mask;
        int                     dn_fd;
        struct file *           dn_filp;
        fl_owner_t              dn_owner;
 };
 
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifdef CONFIG_DNOTIFY
+
 extern void __inode_dir_notify(struct inode *, unsigned long);
-extern void dnotify_flush(struct file *filp, fl_owner_t id);
+extern void dnotify_flush(struct file *, fl_owner_t);
 extern int fcntl_dirnotify(int, struct file *, unsigned long);
-void dnotify_parent(struct dentry *dentry, unsigned long event);
+extern void dnotify_parent(struct dentry *, unsigned long);
 
 static inline void inode_dir_notify(struct inode *inode, unsigned long event)
 {
-       if ((inode)->i_dnotify_mask & (event))
+       if (inode->i_dnotify_mask & (event))
                __inode_dir_notify(inode, event);
 }
+
+#else
+
+static inline void __inode_dir_notify(struct inode *inode, unsigned long event)
+{
+}
+
+static inline void dnotify_flush(struct file *filp, fl_owner_t id)
+{
+}
+
+static inline int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
+{
+       return -EINVAL;
+}
+
+static inline void dnotify_parent(struct dentry *dentry, unsigned long event)
+{
+}
+
+static inline void inode_dir_notify(struct inode *inode, unsigned long event)
+{
+}
+
+#endif /* CONFIG_DNOTIFY */
+
+#endif /* __KERNEL __ */
+
+#endif /* _LINUX_DNOTIFY_H */
index 51a69e3..fd0bc53 100644 (file)
@@ -32,7 +32,8 @@
 typedef enum fe_type {
         FE_QPSK,
         FE_QAM,
-        FE_OFDM
+       FE_OFDM,
+       FE_ATSC
 } fe_type_t;
 
 
@@ -59,7 +60,9 @@ typedef enum fe_caps {
        FE_CAN_BANDWIDTH_AUTO         = 0x40000,
        FE_CAN_GUARD_INTERVAL_AUTO    = 0x80000,
        FE_CAN_HIERARCHY_AUTO         = 0x100000,
-       FE_NEEDS_BENDING              = 0x20000000, // frontend requires frequency bending
+       FE_CAN_8VSB                     = 0x200000,
+       FE_CAN_16VSB                    = 0x400000,
+       FE_NEEDS_BENDING                = 0x20000000, // not supported anymore, don't use (frontend requires frequency bending)
        FE_CAN_RECOVER                = 0x40000000, // frontend can recover from a cable unplug automatically
        FE_CAN_MUTE_TS                = 0x80000000  // frontend can stop spurious TS data output
 } fe_caps_t;
@@ -75,7 +78,7 @@ struct dvb_frontend_info {
        __u32      symbol_rate_min;
         __u32      symbol_rate_max;
        __u32      symbol_rate_tolerance;     /* ppm */
-       __u32      notifier_delay;            /* ms */
+       __u32      notifier_delay;              /* DEPRECATED */
        fe_caps_t  caps;
 };
 
@@ -255,6 +258,8 @@ struct dvb_frontend_event {
 #define FE_GET_FRONTEND            _IOR('o', 77, struct dvb_frontend_parameters)
 #define FE_GET_EVENT               _IOR('o', 78, struct dvb_frontend_event)
 
+#define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */
+
 
 #endif /*_DVBFRONTEND_H_*/
 
index ddd37b8..38afd9d 100644 (file)
@@ -15,7 +15,7 @@ struct eeprom {
        void *dev;
        struct eeprom_ops *ops;
 
-       long            addr;
+       void __iomem *  addr;
 
        unsigned        ee_addr_bits;
 
@@ -43,7 +43,7 @@ enum EEPROM_Cmds {
         EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
 };
 
-void setup_ee_mem_bitbanger(struct eeprom *ee, long memaddr, int eesel_bit, int eeclk_bit, int eedo_bit, int eedi_bit, unsigned polarity)
+void setup_ee_mem_bitbanger(struct eeprom *ee, void __iomem *memaddr, int eesel_bit, int eeclk_bit, int eedo_bit, int eedi_bit, unsigned polarity)
 {
        ee->addr = memaddr;
        ee->eesel = 1 << eesel_bit;
index f7c8446..28f368c 100644 (file)
@@ -45,6 +45,7 @@ extern efs_block_t efs_map_block(struct inode *, efs_block_t);
 extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *efs_get_parent(struct dentry *);
 extern int efs_bmap(struct inode *, int);
 
 #endif /* __EFS_FS_H__ */
index ab631c3..13f4e74 100644 (file)
@@ -14,6 +14,7 @@ enum {
 #define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
 
 /**
+ * struct gnet_stats_basic - byte/packet throughput statistics
  * @bytes: number of seen bytes
  * @packets: number of seen packets
  */
@@ -24,6 +25,7 @@ struct gnet_stats_basic
 };
 
 /**
+ * struct gnet_stats_rate_est - rate estimator
  * @bps: current byte rate
  * @pps: current packet rate
  */
@@ -34,10 +36,12 @@ struct gnet_stats_rate_est
 };
 
 /**
+ * struct gnet_stats_queue - queuing statistics
  * @qlen: queue length
  * @backlog: backlog size of queue
  * @drops: number of dropped packets
  * @requeues: number of requeues
+ * @overlimits: number of enqueues over the limit
  */
 struct gnet_stats_queue
 {
@@ -49,6 +53,7 @@ struct gnet_stats_queue
 };
 
 /**
+ * struct gnet_estimator - rate estimator configuration
  * @interval: sampling period
  * @ewma_log: the log of measurement window weight
  */
index f2bd22e..1c8417a 100644 (file)
@@ -73,7 +73,7 @@ struct gs_port {
 
 
 void gs_put_char(struct tty_struct *tty, unsigned char ch);
-int  gs_write(struct tty_struct *tty, int from_user, 
+int  gs_write(struct tty_struct *tty, 
              const unsigned char *buf, int count);
 int  gs_write_room(struct tty_struct *tty);
 int  gs_chars_in_buffer(struct tty_struct *tty);
index 749992d..ddde66a 100644 (file)
@@ -28,6 +28,7 @@ enum {
        LINUX_RAID_PARTITION = 0xfd,    /* autodetect RAID partition */
 
        SOLARIS_X86_PARTITION = LINUX_SWAP_PARTITION,
+       NEW_SOLARIS_X86_PARTITION = 0xbf,
 
        DM6_AUX1PARTITION = 0x51,       /* no DDO:  use xlated geom */
        DM6_AUX3PARTITION = 0x53,       /* no DDO:  use xlated geom */
@@ -129,13 +130,14 @@ struct gendisk {
 
 /* 
  * Macros to operate on percpu disk statistics:
- * Since writes to disk_stats are serialised through the queue_lock,
- * smp_processor_id() should be enough to get to the per_cpu versions
- * of statistics counters
+ *
+ * The __ variants should only be called in critical sections. The full
+ * variants disable/enable preemption.
  */
 #ifdef CONFIG_SMP
-#define disk_stat_add(gendiskp, field, addnd)  \
+#define __disk_stat_add(gendiskp, field, addnd)        \
        (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd)
+
 #define disk_stat_read(gendiskp, field)                                        \
 ({                                                                     \
        typeof(gendiskp->dkstats->field) res = 0;                       \
@@ -159,7 +161,8 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)   {
 }              
                                
 #else
-#define disk_stat_add(gendiskp, field, addnd) (gendiskp->dkstats.field += addnd)
+#define __disk_stat_add(gendiskp, field, addnd) \
+                               (gendiskp->dkstats.field += addnd)
 #define disk_stat_read(gendiskp, field)        (gendiskp->dkstats.field)
 
 static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)      {
@@ -167,8 +170,21 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)  {
 }
 #endif
 
-#define disk_stat_inc(gendiskp, field) disk_stat_add(gendiskp, field, 1)
+#define disk_stat_add(gendiskp, field, addnd)                  \
+       do {                                                    \
+               preempt_disable();                              \
+               __disk_stat_add(gendiskp, field, addnd);        \
+               preempt_enable();                               \
+       } while (0)
+
+#define __disk_stat_dec(gendiskp, field) __disk_stat_add(gendiskp, field, -1)
 #define disk_stat_dec(gendiskp, field) disk_stat_add(gendiskp, field, -1)
+
+#define __disk_stat_inc(gendiskp, field) __disk_stat_add(gendiskp, field, 1)
+#define disk_stat_inc(gendiskp, field) disk_stat_add(gendiskp, field, 1)
+
+#define __disk_stat_sub(gendiskp, field, subnd) \
+               __disk_stat_add(gendiskp, field, -subnd)
 #define disk_stat_sub(gendiskp, field, subnd) \
                disk_stat_add(gendiskp, field, -subnd)
 
index 7e1aad3..eae45cc 100644 (file)
@@ -5,6 +5,40 @@
 #include <linux/smp_lock.h>
 #include <asm/hardirq.h>
 
+/*
+ * 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)
+ *
+ * The hardirq count can be overridden per architecture, the default is:
+ *
+ * - bits 16-27 are the hardirq count (max # of hardirqs: 4096)
+ * - ( bit 28 is the PREEMPT_ACTIVE flag. )
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * SOFTIRQ_MASK: 0x0000ff00
+ * HARDIRQ_MASK: 0x0fff0000
+ */
+#define PREEMPT_BITS   8
+#define SOFTIRQ_BITS   8
+
+#ifndef HARDIRQ_BITS
+#define HARDIRQ_BITS   12
+/*
+ * 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
+#endif
+
+#define PREEMPT_SHIFT  0
+#define SOFTIRQ_SHIFT  (PREEMPT_SHIFT + PREEMPT_BITS)
+#define HARDIRQ_SHIFT  (SOFTIRQ_SHIFT + SOFTIRQ_BITS)
+
 #define __IRQ_MASK(x)  ((1UL << (x))-1)
 
 #define PREEMPT_MASK   (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
@@ -43,4 +77,12 @@ extern void synchronize_irq(unsigned int irq);
 # define synchronize_irq(irq)  barrier()
 #endif
 
+#ifdef CONFIG_GENERIC_HARDIRQS
+#define nmi_enter()            (preempt_count() += HARDIRQ_OFFSET)
+#define nmi_exit()             (preempt_count() -= HARDIRQ_OFFSET)
+
+#define irq_enter()            (preempt_count() += HARDIRQ_OFFSET)
+extern void irq_exit(void);
+#endif
+
 #endif /* LINUX_HARDIRQ_H */
index 54ad63b..b5d6600 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef _LINUX_HDREG_H
 #define _LINUX_HDREG_H
 
+#ifdef __KERNEL__
+#include <linux/ata.h>
+
 /*
  * This file contains some defines for the AT-hd-controller.
  * Various sources.
@@ -55,7 +58,7 @@
 #define IO                     0x02
 #define REL                    0x04
 #define TAG_MASK               0xf8
-
+#endif /* __KERNEL__ */
 
 /*
  * Command Header sizes for IOCTL commands
@@ -328,27 +331,6 @@ typedef struct hd_drive_hob_hdr {
 /* WIN_SETFEATURES sub-commands */
 #define SETFEATURES_EN_8BIT    0x01    /* Enable 8-Bit Transfers */
 #define SETFEATURES_EN_WCACHE  0x02    /* Enable write cache */
-#define SETFEATURES_XFER       0x03    /* Set transfer mode */
-#      define XFER_UDMA_7      0x47    /* 0100|0111 */
-#      define XFER_UDMA_6      0x46    /* 0100|0110 */
-#      define XFER_UDMA_5      0x45    /* 0100|0101 */
-#      define XFER_UDMA_4      0x44    /* 0100|0100 */
-#      define XFER_UDMA_3      0x43    /* 0100|0011 */
-#      define XFER_UDMA_2      0x42    /* 0100|0010 */
-#      define XFER_UDMA_1      0x41    /* 0100|0001 */
-#      define XFER_UDMA_0      0x40    /* 0100|0000 */
-#      define XFER_MW_DMA_2    0x22    /* 0010|0010 */
-#      define XFER_MW_DMA_1    0x21    /* 0010|0001 */
-#      define XFER_MW_DMA_0    0x20    /* 0010|0000 */
-#      define XFER_SW_DMA_2    0x12    /* 0001|0010 */
-#      define XFER_SW_DMA_1    0x11    /* 0001|0001 */
-#      define XFER_SW_DMA_0    0x10    /* 0001|0000 */
-#      define XFER_PIO_4       0x0C    /* 0000|1100 */
-#      define XFER_PIO_3       0x0B    /* 0000|1011 */
-#      define XFER_PIO_2       0x0A    /* 0000|1010 */
-#      define XFER_PIO_1       0x09    /* 0000|1001 */
-#      define XFER_PIO_0       0x08    /* 0000|1000 */
-#      define XFER_PIO_SLOW    0x00    /* 0000|0000 */
 #define SETFEATURES_DIS_DEFECT 0x04    /* Disable Defect Management */
 #define SETFEATURES_EN_APM     0x05    /* Enable advanced power management */
 #define SETFEATURES_EN_SAME_R  0x22    /* for a region ATA-1 */
index 142de4a..2723819 100644 (file)
@@ -112,6 +112,7 @@ struct hpet_task {
 };
 
 struct hpet_data {
+       unsigned long hd_phys_address;
        void __iomem *hd_address;
        unsigned short hd_nirqs;
        unsigned short hd_flags;
index 6db8f91..21b6252 100644 (file)
@@ -42,51 +42,25 @@ struct i2c_force_data {
 /* A structure containing the detect information.
    normal_i2c: filled in by the module writer. Terminated by I2C_CLIENT_ISA_END.
      A list of I2C addresses which should normally be examined.
-   normal_i2c_range: filled in by the module writer. Terminated by 
-     I2C_CLIENT_ISA_END
-     A list of pairs of I2C addresses, each pair being an inclusive range of
-     addresses which should normally be examined.
    normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
      A list of ISA addresses which should normally be examined.
-   normal_isa_range: filled in by the module writer. Terminated by 
-     SENSORS_ISA_END
-     A list of triples. The first two elements are ISA addresses, being an
-     range of addresses which should normally be examined. The third is the
-     modulo parameter: only addresses which are 0 module this value relative
-     to the first address of the range are actually considered.
    probe: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END values.
      A list of pairs. The first value is a bus number (ANY_I2C_ISA_BUS for
      the ISA bus, -1 for any I2C bus), the second is the address. These
      addresses are also probed, as if they were in the 'normal' list.
-   probe_range: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END 
-     values.
-     A list of triples. The first value is a bus number (ANY_I2C_ISA_BUS for
-     the ISA bus, -1 for any I2C bus), the second and third are addresses. 
-     These form an inclusive range of addresses that are also probed, as
-     if they were in the 'normal' list.
    ignore: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END values.
      A list of pairs. The first value is a bus number (ANY_I2C_ISA_BUS for
      the ISA bus, -1 for any I2C bus), the second is the I2C address. These
      addresses are never probed. This parameter overrules 'normal' and 
      'probe', but not the 'force' lists.
-   ignore_range: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END 
-      values.
-     A list of triples. The first value is a bus number (ANY_I2C_ISA_BUS for
-     the ISA bus, -1 for any I2C bus), the second and third are addresses. 
-     These form an inclusive range of I2C addresses that are never probed.
-     This parameter overrules 'normal' and 'probe', but not the 'force' lists.
    force_data: insmod parameters. A list, ending with an element of which
      the force field is NULL.
 */
 struct i2c_address_data {
        unsigned short *normal_i2c;
-       unsigned short *normal_i2c_range;
        unsigned int *normal_isa;
-       unsigned int *normal_isa_range;
        unsigned short *probe;
-       unsigned short *probe_range;
        unsigned short *ignore;
-       unsigned short *ignore_range;
        struct i2c_force_data *forces;
 };
 
@@ -100,23 +74,13 @@ struct i2c_address_data {
 #define SENSORS_INSMOD \
   I2C_CLIENT_MODULE_PARM(probe, \
                       "List of adapter,address pairs to scan additionally"); \
-  I2C_CLIENT_MODULE_PARM(probe_range, \
-                      "List of adapter,start-addr,end-addr triples to scan " \
-                      "additionally"); \
   I2C_CLIENT_MODULE_PARM(ignore, \
                       "List of adapter,address pairs not to scan"); \
-  I2C_CLIENT_MODULE_PARM(ignore_range, \
-                      "List of adapter,start-addr,end-addr triples not to " \
-                      "scan"); \
        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 =                probe,                  \
-                       .probe_range =          probe_range,            \
                        .ignore =               ignore,                 \
-                       .ignore_range =         ignore_range,           \
                        .forces =               forces,                 \
                }
 
index 6242409..974835e 100644 (file)
 */
 
 /*
-    Legal val values 00 - 1F.
+    AMD Opteron processors don't follow the Intel VRM spec.
+    I'm going to "make up" 2.4 as the VRM spec for the Opterons.
+    No good reason just a mnemonic for the 24x Opteron processor
+    series
+
+    Opteron VID encoding is:
+
+       00000  =  1.550 V
+       00001  =  1.525 V
+        . . . .
+       11110  =  0.800 V
+       11111  =  0.000 V (off)
+ */
+
+/*
+    Legal val values 0x00 - 0x1f; except for VRD 10.0, 0x00 - 0x3f.
     vrm is the Intel VRM document version.
     Note: vrm version is scaled by 10 and the return value is scaled by 1000
     to avoid floating point in the kernel.
@@ -41,9 +56,28 @@ int i2c_which_vrm(void);
 
 static inline int vid_from_reg(int val, int vrm)
 {
+       int vid;
+
        switch(vrm) {
+
        case  0:
                return 0;
+
+       case 100:               /* VRD 10.0 */
+               if((val & 0x1f) == 0x1f)
+                       return 0;
+               if((val & 0x1f) <= 0x09 || val == 0x0a)
+                       vid = 10875 - (val & 0x1f) * 250;
+               else
+                       vid = 18625 - (val & 0x1f) * 250;
+               if(val & 0x20)
+                       vid -= 125;
+               vid /= 10;      /* only return 3 dec. places for now */
+               return vid;
+
+       case 24:                /* Opteron processor */
+               return(val == 0x1f ? 0 : 1550 - val * 25);
+
        case 91:                /* VRM 9.1 */
        case 90:                /* VRM 9.0 */
                return(val == 0x1f ? 0 :
index d9ab5cd..f0b571f 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef _LINUX_ICMP_H
 #define        _LINUX_ICMP_H
 
+#include <linux/types.h>
+
 #define ICMP_ECHOREPLY         0       /* Echo Reply                   */
 #define ICMP_DEST_UNREACH      3       /* Destination Unreachable      */
 #define ICMP_SOURCE_QUENCH     4       /* Source Quench                */
index 6ee8b04..572aff7 100644 (file)
@@ -92,7 +92,7 @@ struct npioctl {
 
 /* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
 struct ppp_option_data {
-       __u8    *ptr;
+       __u8    __user *ptr;
        __u32   length;
        int     transmit;
 };
index 29b6e10..62a9d89 100644 (file)
@@ -366,7 +366,9 @@ enum vlan_ioctl_cmds {
        GET_VLAN_INGRESS_PRIORITY_CMD,
        GET_VLAN_EGRESS_PRIORITY_CMD,
        SET_VLAN_NAME_TYPE_CMD,
-       SET_VLAN_FLAG_CMD
+       SET_VLAN_FLAG_CMD,
+       GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */
+       GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */
 };
 
 enum vlan_name_types {
index af4fa41..3b5e9fd 100644 (file)
@@ -43,6 +43,8 @@
 #define _LINUX_INET_H
 
 #ifdef __KERNEL__
+#include <linux/types.h>
+
 extern __u32 in_aton(const char *str);
 #endif
 #endif /* _LINUX_INET_H */
index 43cb25e..11e0c12 100644 (file)
@@ -473,6 +473,28 @@ struct input_absinfo {
 #define KEY_INS_LINE           0x1c2
 #define KEY_DEL_LINE           0x1c3
 
+#define KEY_FN                 0x1d0
+#define KEY_FN_ESC             0x1d1
+#define KEY_FN_F1              0x1d2
+#define KEY_FN_F2              0x1d3
+#define KEY_FN_F3              0x1d4
+#define KEY_FN_F4              0x1d5
+#define KEY_FN_F5              0x1d6
+#define KEY_FN_F6              0x1d7
+#define KEY_FN_F7              0x1d8
+#define KEY_FN_F8              0x1d9
+#define KEY_FN_F9              0x1da
+#define KEY_FN_F10             0x1db
+#define KEY_FN_F11             0x1dc
+#define KEY_FN_F12             0x1dd
+#define KEY_FN_1               0x1de
+#define KEY_FN_2               0x1df
+#define KEY_FN_D               0x1e0
+#define KEY_FN_E               0x1e1
+#define KEY_FN_F               0x1e2
+#define KEY_FN_S               0x1e3
+#define KEY_FN_B               0x1e4
+
 #define KEY_MAX                        0x1ff
 
 /*
index 363aef7..62d0420 100644 (file)
@@ -82,6 +82,11 @@ struct resource_list {
 #define IORESOURCE_MEM_SHADOWABLE      (1<<5)  /* dup: IORESOURCE_SHADOWABLE */
 #define IORESOURCE_MEM_EXPANSIONROM    (1<<6)
 
+/* PCI ROM control bits (IORESOURCE_BITS) */
+#define IORESOURCE_ROM_ENABLE          (1<<0)  /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */
+#define IORESOURCE_ROM_SHADOW          (1<<1)  /* ROM is copy at C000:0 */
+#define IORESOURCE_ROM_COPY            (1<<2)  /* ROM is alloc'd copy, resource field overlaid */
+
 /* PC/ISA/whatever - the normal PC address spaces: IO and memory */
 extern struct resource ioport_resource;
 extern struct resource iomem_resource;
index 46d8b7e..e2f9350 100644 (file)
@@ -14,7 +14,8 @@
 #define _LINUX_IPV6_ROUTE_H
 
 #define RTF_DEFAULT    0x00010000      /* default - learned via ND     */
-#define RTF_ALLONLINK  0x00020000      /* fallback, no routers on link */
+#define RTF_ALLONLINK  0x00020000      /* (deprecated and will be removed)
+                                          fallback, no routers on link */
 #define RTF_ADDRCONF   0x00040000      /* addrconf route - RA          */
 #define RTF_PREFIX_RT  0x00080000      /* A prefix only route - RA     */
 
index 5bc740d..20b1d95 100644 (file)
@@ -13,6 +13,7 @@
 
 #if !defined(CONFIG_ARCH_S390)
 
+#include <linux/linkage.h>
 #include <linux/cache.h>
 #include <linux/spinlock.h>
 #include <linux/cpumask.h>
@@ -71,7 +72,22 @@ extern irq_desc_t irq_desc [NR_IRQS];
 
 #include <asm/hw_irq.h> /* the arch dependent stuff */
 
-extern int setup_irq(unsigned int , struct irqaction * );
+extern int setup_irq(unsigned int irq, struct irqaction * new);
+
+#ifdef CONFIG_GENERIC_HARDIRQS
+extern cpumask_t irq_affinity[NR_IRQS];
+extern int no_irq_affinity;
+extern int noirqdebug_setup(char *str);
+
+extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+                                      struct irqaction *action);
+extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
+extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret);
+extern void report_bad_irq(unsigned int irq, irq_desc_t *desc, int action_ret);
+extern int can_request_irq(unsigned int irq, unsigned long irqflags);
+
+extern void init_irq_proc(void);
+#endif
 
 extern hw_irq_controller no_irq_type;  /* needed in every arch ? */
 
index 459630f..d45eff8 100644 (file)
@@ -3,10 +3,72 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/seqlock.h>
-#include <asm/system.h>
+#include <linux/time.h>
+#include <linux/timex.h>
 #include <asm/param.h>                 /* for HZ */
+#include <asm/div64.h>
+
+#ifndef div_long_long_rem
+#define div_long_long_rem(dividend,divisor,remainder) \
+({                                                     \
+       u64 result = dividend;                          \
+       *remainder = do_div(result,divisor);            \
+       result;                                         \
+})
+#endif
+
+/*
+ * The following defines establish the engineering parameters of the PLL
+ * model. The HZ variable establishes the timer interrupt frequency, 100 Hz
+ * for the SunOS kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the
+ * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the
+ * nearest power of two in order to avoid hardware multiply operations.
+ */
+#if HZ >= 12 && HZ < 24
+# define SHIFT_HZ      4
+#elif HZ >= 24 && HZ < 48
+# define SHIFT_HZ      5
+#elif HZ >= 48 && HZ < 96
+# define SHIFT_HZ      6
+#elif HZ >= 96 && HZ < 192
+# define SHIFT_HZ      7
+#elif HZ >= 192 && HZ < 384
+# define SHIFT_HZ      8
+#elif HZ >= 384 && HZ < 768
+# define SHIFT_HZ      9
+#elif HZ >= 768 && HZ < 1536
+# define SHIFT_HZ      10
+#else
+# error You lose.
+#endif
+
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
+
+/* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can
+ * improve accuracy by shifting LSH bits, hence calculating:
+ *     (NOM << LSH) / DEN
+ * This however means trouble for large NOM, because (NOM << LSH) may no
+ * longer fit in 32 bits. The following way of calculating this gives us
+ * some slack, under the following conditions:
+ *   - (NOM / DEN) fits in (32 - LSH) bits.
+ *   - (NOM % DEN) fits in (32 - LSH) bits.
+ */
+#define SH_DIV(NOM,DEN,LSH) (   ((NOM / DEN) << LSH)                    \
+                             + (((NOM % DEN) << LSH) + DEN / 2) / DEN)
+
+/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
+#define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
+
+/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */
+#define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8))
+
+/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
+#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
+
+/* TICK_USEC_TO_NSEC is the time between ticks in nsec assuming real ACTHZ and */
+/* a value TUSEC for TICK_USEC (can be set bij adjtimex)               */
+#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV (TUSEC * USER_HZ * 1000, ACTHZ, 8))
 
 /*
  * The 64-bit value is not volatile - you MUST NOT read it
@@ -50,4 +112,320 @@ static inline u64 get_jiffies_64(void)
         ((long)(a) - (long)(b) >= 0))
 #define time_before_eq(a,b)    time_after_eq(b,a)
 
+/*
+ * Have the 32 bit jiffies value wrap 5 minutes after boot
+ * so jiffies wrap bugs show up earlier.
+ */
+#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
+
+/*
+ * Change timeval to jiffies, trying to avoid the
+ * most obvious overflows..
+ *
+ * And some not so obvious.
+ *
+ * Note that we don't want to return MAX_LONG, because
+ * for various timeout reasons we often end up having
+ * to wait "jiffies+1" in order to guarantee that we wait
+ * at _least_ "jiffies" - so "jiffies+1" had better still
+ * be positive.
+ */
+#define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
+
+/*
+ * We want to do realistic conversions of time so we need to use the same
+ * values the update wall clock code uses as the jiffies size.  This value
+ * is: TICK_NSEC (which is defined in timex.h).  This
+ * is a constant and is in nanoseconds.  We will used scaled math
+ * with a set of scales defined here as SEC_JIFFIE_SC,  USEC_JIFFIE_SC and
+ * NSEC_JIFFIE_SC.  Note that these defines contain nothing but
+ * constants and so are computed at compile time.  SHIFT_HZ (computed in
+ * timex.h) adjusts the scaling for different HZ values.
+
+ * Scaled math???  What is that?
+ *
+ * Scaled math is a way to do integer math on values that would,
+ * otherwise, either overflow, underflow, or cause undesired div
+ * instructions to appear in the execution path.  In short, we "scale"
+ * up the operands so they take more bits (more precision, less
+ * underflow), do the desired operation and then "scale" the result back
+ * by the same amount.  If we do the scaling by shifting we avoid the
+ * costly mpy and the dastardly div instructions.
+
+ * Suppose, for example, we want to convert from seconds to jiffies
+ * where jiffies is defined in nanoseconds as NSEC_PER_JIFFIE.  The
+ * simple math is: jiff = (sec * NSEC_PER_SEC) / NSEC_PER_JIFFIE; We
+ * observe that (NSEC_PER_SEC / NSEC_PER_JIFFIE) is a constant which we
+ * might calculate at compile time, however, the result will only have
+ * about 3-4 bits of precision (less for smaller values of HZ).
+ *
+ * So, we scale as follows:
+ * jiff = (sec) * (NSEC_PER_SEC / NSEC_PER_JIFFIE);
+ * jiff = ((sec) * ((NSEC_PER_SEC * SCALE)/ NSEC_PER_JIFFIE)) / SCALE;
+ * Then we make SCALE a power of two so:
+ * jiff = ((sec) * ((NSEC_PER_SEC << SCALE)/ NSEC_PER_JIFFIE)) >> SCALE;
+ * Now we define:
+ * #define SEC_CONV = ((NSEC_PER_SEC << SCALE)/ NSEC_PER_JIFFIE))
+ * jiff = (sec * SEC_CONV) >> SCALE;
+ *
+ * Often the math we use will expand beyond 32-bits so we tell C how to
+ * do this and pass the 64-bit result of the mpy through the ">> SCALE"
+ * which should take the result back to 32-bits.  We want this expansion
+ * to capture as much precision as possible.  At the same time we don't
+ * want to overflow so we pick the SCALE to avoid this.  In this file,
+ * that means using a different scale for each range of HZ values (as
+ * defined in timex.h).
+ *
+ * For those who want to know, gcc will give a 64-bit result from a "*"
+ * operator if the result is a long long AND at least one of the
+ * operands is cast to long long (usually just prior to the "*" so as
+ * not to confuse it into thinking it really has a 64-bit operand,
+ * which, buy the way, it can do, but it take more code and at least 2
+ * mpys).
+
+ * We also need to be aware that one second in nanoseconds is only a
+ * couple of bits away from overflowing a 32-bit word, so we MUST use
+ * 64-bits to get the full range time in nanoseconds.
+
+ */
+
+/*
+ * Here are the scales we will use.  One for seconds, nanoseconds and
+ * microseconds.
+ *
+ * Within the limits of cpp we do a rough cut at the SEC_JIFFIE_SC and
+ * check if the sign bit is set.  If not, we bump the shift count by 1.
+ * (Gets an extra bit of precision where we can use it.)
+ * We know it is set for HZ = 1024 and HZ = 100 not for 1000.
+ * Haven't tested others.
+
+ * Limits of cpp (for #if expressions) only long (no long long), but
+ * then we only need the most signicant bit.
+ */
+
+#define SEC_JIFFIE_SC (31 - SHIFT_HZ)
+#if !((((NSEC_PER_SEC << 2) / TICK_NSEC) << (SEC_JIFFIE_SC - 2)) & 0x80000000)
+#undef SEC_JIFFIE_SC
+#define SEC_JIFFIE_SC (32 - SHIFT_HZ)
+#endif
+#define NSEC_JIFFIE_SC (SEC_JIFFIE_SC + 29)
+#define USEC_JIFFIE_SC (SEC_JIFFIE_SC + 19)
+#define SEC_CONVERSION ((unsigned long)((((u64)NSEC_PER_SEC << SEC_JIFFIE_SC) +\
+                                TICK_NSEC -1) / (u64)TICK_NSEC))
+
+#define NSEC_CONVERSION ((unsigned long)((((u64)1 << NSEC_JIFFIE_SC) +\
+                                        TICK_NSEC -1) / (u64)TICK_NSEC))
+#define USEC_CONVERSION  \
+                    ((unsigned long)((((u64)NSEC_PER_USEC << USEC_JIFFIE_SC) +\
+                                        TICK_NSEC -1) / (u64)TICK_NSEC))
+/*
+ * USEC_ROUND is used in the timeval to jiffie conversion.  See there
+ * for more details.  It is the scaled resolution rounding value.  Note
+ * that it is a 64-bit value.  Since, when it is applied, we are already
+ * in jiffies (albit scaled), it is nothing but the bits we will shift
+ * off.
+ */
+#define USEC_ROUND (u64)(((u64)1 << USEC_JIFFIE_SC) - 1)
+/*
+ * The maximum jiffie value is (MAX_INT >> 1).  Here we translate that
+ * into seconds.  The 64-bit case will overflow if we are not careful,
+ * so use the messy SH_DIV macro to do it.  Still all constants.
+ */
+#if BITS_PER_LONG < 64
+# define MAX_SEC_IN_JIFFIES \
+       (long)((u64)((u64)MAX_JIFFY_OFFSET * TICK_NSEC) / NSEC_PER_SEC)
+#else  /* take care of overflow on 64 bits machines */
+# define MAX_SEC_IN_JIFFIES \
+       (SH_DIV((MAX_JIFFY_OFFSET >> SEC_JIFFIE_SC) * TICK_NSEC, NSEC_PER_SEC, 1) - 1)
+
+#endif
+
+/*
+ * Convert jiffies to milliseconds and back.
+ *
+ * Avoid unnecessary multiplications/divisions in the
+ * two most common HZ cases:
+ */
+static inline unsigned int jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+       return (1000 / HZ) * j;
+#elif HZ > 1000 && !(HZ % 1000)
+       return (j + (HZ / 1000) - 1)/(HZ / 1000);
+#else
+       return (j * 1000) / HZ;
+#endif
+}
+
+static inline unsigned int jiffies_to_usecs(const unsigned long j)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+       return (1000000 / HZ) * j;
+#elif HZ > 1000 && !(HZ % 1000)
+       return (j*1000 + (HZ - 1000))/(HZ / 1000);
+#else
+       return (j * 1000000) / HZ;
+#endif
+}
+
+static inline unsigned long msecs_to_jiffies(const unsigned int m)
+{
+       if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
+               return MAX_JIFFY_OFFSET;
+#if HZ <= 1000 && !(1000 % HZ)
+       return (m + (1000 / HZ) - 1) / (1000 / HZ);
+#elif HZ > 1000 && !(HZ % 1000)
+       return m * (HZ / 1000);
+#else
+       return (m * HZ + 999) / 1000;
+#endif
+}
+
+/*
+ * The TICK_NSEC - 1 rounds up the value to the next resolution.  Note
+ * that a remainder subtract here would not do the right thing as the
+ * resolution values don't fall on second boundries.  I.e. the line:
+ * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding.
+ *
+ * Rather, we just shift the bits off the right.
+ *
+ * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec
+ * value to a scaled second value.
+ */
+static __inline__ unsigned long
+timespec_to_jiffies(const struct timespec *value)
+{
+       unsigned long sec = value->tv_sec;
+       long nsec = value->tv_nsec + TICK_NSEC - 1;
+
+       if (sec >= MAX_SEC_IN_JIFFIES){
+               sec = MAX_SEC_IN_JIFFIES;
+               nsec = 0;
+       }
+       return (((u64)sec * SEC_CONVERSION) +
+               (((u64)nsec * NSEC_CONVERSION) >>
+                (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
+
+}
+
+static __inline__ void
+jiffies_to_timespec(const unsigned long jiffies, struct timespec *value)
+{
+       /*
+        * Convert jiffies to nanoseconds and separate with
+        * one divide.
+        */
+       u64 nsec = (u64)jiffies * TICK_NSEC;
+       value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_nsec);
+}
+
+/* Same for "timeval"
+ *
+ * Well, almost.  The problem here is that the real system resolution is
+ * in nanoseconds and the value being converted is in micro seconds.
+ * Also for some machines (those that use HZ = 1024, in-particular),
+ * there is a LARGE error in the tick size in microseconds.
+
+ * The solution we use is to do the rounding AFTER we convert the
+ * microsecond part.  Thus the USEC_ROUND, the bits to be shifted off.
+ * Instruction wise, this should cost only an additional add with carry
+ * instruction above the way it was done above.
+ */
+static __inline__ unsigned long
+timeval_to_jiffies(const struct timeval *value)
+{
+       unsigned long sec = value->tv_sec;
+       long usec = value->tv_usec;
+
+       if (sec >= MAX_SEC_IN_JIFFIES){
+               sec = MAX_SEC_IN_JIFFIES;
+               usec = 0;
+       }
+       return (((u64)sec * SEC_CONVERSION) +
+               (((u64)usec * USEC_CONVERSION + USEC_ROUND) >>
+                (USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
+}
+
+static __inline__ void
+jiffies_to_timeval(const unsigned long jiffies, struct timeval *value)
+{
+       /*
+        * Convert jiffies to nanoseconds and separate with
+        * one divide.
+        */
+       u64 nsec = (u64)jiffies * TICK_NSEC;
+       value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_usec);
+       value->tv_usec /= NSEC_PER_USEC;
+}
+
+/*
+ * Convert jiffies/jiffies_64 to clock_t and back.
+ */
+static inline clock_t jiffies_to_clock_t(long x)
+{
+#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
+       return x / (HZ / USER_HZ);
+#else
+       u64 tmp = (u64)x * TICK_NSEC;
+       do_div(tmp, (NSEC_PER_SEC / USER_HZ));
+       return (long)tmp;
+#endif
+}
+
+static inline unsigned long clock_t_to_jiffies(unsigned long x)
+{
+#if (HZ % USER_HZ)==0
+       if (x >= ~0UL / (HZ / USER_HZ))
+               return ~0UL;
+       return x * (HZ / USER_HZ);
+#else
+       u64 jif;
+
+       /* Don't worry about loss of precision here .. */
+       if (x >= ~0UL / HZ * USER_HZ)
+               return ~0UL;
+
+       /* .. but do try to contain it here */
+       jif = x * (u64) HZ;
+       do_div(jif, USER_HZ);
+       return jif;
+#endif
+}
+
+static inline u64 jiffies_64_to_clock_t(u64 x)
+{
+#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
+       do_div(x, HZ / USER_HZ);
+#else
+       /*
+        * There are better ways that don't overflow early,
+        * but even this doesn't overflow in hundreds of years
+        * in 64 bits, so..
+        */
+       x *= TICK_NSEC;
+       do_div(x, (NSEC_PER_SEC / USER_HZ));
+#endif
+       return x;
+}
+
+static inline u64 nsec_to_clock_t(u64 x)
+{
+#if (NSEC_PER_SEC % USER_HZ) == 0
+       do_div(x, (NSEC_PER_SEC / USER_HZ));
+#elif (USER_HZ % 512) == 0
+       x *= USER_HZ/512;
+       do_div(x, (NSEC_PER_SEC / 512));
+#else
+       /*
+         * max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024,
+         * overflow after 64.99 years.
+         * exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ...
+         */
+       x *= 9;
+       do_div(x, (unsigned long)((9ull * NSEC_PER_SEC + (USER_HZ/2))
+                                 / USER_HZ));
+#endif
+       return x;
+}
+
 #endif
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
index 172b7f4..3177a7f 100644 (file)
@@ -64,7 +64,7 @@ struct kprobe {
        kprobe_opcode_t opcode;
 
        /* copy of the original instruction */
-       kprobe_opcode_t insn[MAX_INSN_SIZE];
+       struct arch_specific_insn ainsn;
 };
 
 /*
@@ -94,7 +94,8 @@ static inline int kprobe_running(void)
        return kprobe_cpu == smp_processor_id();
 }
 
-extern void arch_prepare_kprobe(struct kprobe *p);
+extern int arch_prepare_kprobe(struct kprobe *p);
+extern void arch_remove_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 */
index 94bed0f..7cad532 100644 (file)
@@ -568,8 +568,6 @@ static inline void hlist_del_init(struct hlist_node *n)
        }
 }
 
-#define hlist_del_rcu_init hlist_del_init
-
 static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
 {
        struct hlist_node *first = h->first;
index cde7dba..bbc93ae 100644 (file)
 
 #include <asm/io.h>
 #include <linux/rtc.h>                 /* get the user-level API */
-#include <linux/spinlock.h>            /* spinlock_t */
 #include <asm/mc146818rtc.h>           /* register access macros */
 
+#ifdef __KERNEL__
+#include <linux/spinlock.h>            /* spinlock_t */
 extern spinlock_t rtc_lock;            /* serialize CMOS RAM access */
+#endif
 
 /**********************************************************************
  * register summary
index 9835ac2..8480aef 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/bitmap.h>
 #include <linux/slab.h>
 #include <linux/rbtree.h>
-#include <asm/semaphore.h>
+#include <linux/spinlock.h>
 
 struct vm_area_struct;
 
@@ -134,13 +134,13 @@ struct sp_node {
 
 struct shared_policy {
        struct rb_root root;
-       struct semaphore sem;
+       spinlock_t lock;
 };
 
 static inline void mpol_shared_policy_init(struct shared_policy *info)
 {
        info->root = RB_ROOT;
-       init_MUTEX(&info->sem);
+       spin_lock_init(&info->lock);
 }
 
 int mpol_set_shared_policy(struct shared_policy *info,
index dc2c12d..11ec45e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Motion Eye video4linux driver for Sony Vaio PictureBook
  *
  * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
@@ -8,20 +8,20 @@
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
  * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
- * 
+ *
  * Some parts borrowed from various video4linux drivers, especially
  * bttv-driver.c and zoran.c, see original files for credits.
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the 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.
@@ -56,4 +56,11 @@ struct meye_params {
 /* get a jpeg compressed snapshot */
 #define MEYEIOC_STILLJCAPT     _IOR ('v', BASE_VIDIOCPRIVATE+5, int)
 
+/* V4L2 private controls */
+#define V4L2_CID_AGC           V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_SHARPNESS     (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PICTURE       (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_JPEGQUAL      (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_FRAMERATE     (V4L2_CID_PRIVATE_BASE + 4)
+
 #endif
index c288ae6..1fa1cb3 100644 (file)
@@ -57,7 +57,7 @@ struct mmc_data {
        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 */
+       struct request          *req __attribute__((deprecated));/* request structure (use the sg list instead) */
        unsigned int            error;          /* data error */
        unsigned int            flags;
 
@@ -69,6 +69,9 @@ struct mmc_data {
 
        struct mmc_command      *stop;          /* stop command */
        struct mmc_request      *mrq;           /* assoicated request */
+
+       unsigned int            sg_len;         /* size of scatter list */
+       struct scatterlist      *sg;            /* I/O scatter list */
 };
 
 struct mmc_request {
index f2383d2..b50018c 100644 (file)
@@ -7,10 +7,14 @@
  * MS-DOS file system inode data in memory
  */
 
+#define FAT_CACHE_VALID        0       /* special case for valid cache */
+
 struct msdos_inode_info {
-       /* cache of lastest accessed cluster */
-       int file_cluster;       /* cluster number in the file. */
-       int disk_cluster;       /* cluster number on disk. */
+       spinlock_t cache_lru_lock;
+       struct list_head cache_lru;
+       int nr_caches;
+       /* for avoiding the race between fat_free() and fat_get_cluster() */
+       unsigned int cache_valid_id;
 
        loff_t mmu_private;
        int i_start;    /* first cluster or 0 */
@@ -18,7 +22,7 @@ struct msdos_inode_info {
        int i_attrs;    /* unused attribute bits */
        int i_ctime_ms; /* unused change time in milliseconds */
        loff_t i_pos;   /* on-disk position of directory entry or 0 */
-       struct list_head i_fat_hash;    /* hash by i_location */
+       struct hlist_node i_fat_hash;   /* hash by i_location */
        struct inode vfs_inode;
 };
 
index c79a172..3310996 100644 (file)
@@ -26,14 +26,9 @@ struct fat_mount_options {
                 nocase:1;        /* Does this need case conversion? 0=need case conversion*/
 };
 
-#define FAT_CACHE_NR   8 /* number of FAT cache */
-
-struct fat_cache {
-       int start_cluster; /* first cluster of the chain. */
-       int file_cluster; /* cluster number in the file. */
-       int disk_cluster; /* cluster number on disk. */
-       struct fat_cache *next; /* next cache entry */
-};
+#define FAT_HASH_BITS  8
+#define FAT_HASH_SIZE  (1UL << FAT_HASH_BITS)
+#define FAT_HASH_MASK  (FAT_HASH_SIZE-1)
 
 struct msdos_sb_info {
        unsigned short sec_per_clus; /* sectors/cluster */
@@ -58,8 +53,8 @@ struct msdos_sb_info {
        int dir_per_block;           /* dir entries per block */
        int dir_per_block_bits;      /* log2(dir_per_block) */
 
-       spinlock_t cache_lock;
-       struct fat_cache cache_array[FAT_CACHE_NR], *cache;
+       spinlock_t inode_hash_lock;
+       struct hlist_head inode_hashtable[FAT_HASH_SIZE];
 };
 
 #endif
index 0ab4590..61dad57 100644 (file)
@@ -18,7 +18,7 @@ enum tcp_conntrack {
 };
 
 /* Window scaling is advertised by the sender */
-#define IP_CT_TCP_STATE_FLAG_WINDOW_SCALE      0x01
+#define IP_CT_TCP_FLAG_WINDOW_SCALE            0x01
 
 /* SACK is permitted by the sender */
 #define IP_CT_TCP_FLAG_SACK_PERM               0x02
index e817958..f343239 100644 (file)
@@ -18,7 +18,7 @@ struct ip_nat_protocol
        /* Do a packet translation according to the ip_nat_proto_manip
         * and manip type.  Return true if succeeded. */
        int (*manip_pkt)(struct sk_buff **pskb,
-                        unsigned int hdroff,
+                        unsigned int iphdroff,
                         const struct ip_conntrack_manip *manip,
                         enum ip_nat_manip_type maniptype);
 
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_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*/
index 96974ab..5ca8a8d 100644 (file)
@@ -35,6 +35,7 @@
 #define NFS4_FH_VOL_RENAME             0x0008
 
 #define NFS4_OPEN_RESULT_CONFIRM 0x0002
+#define NFS4_OPEN_RESULT_LOCKTYPE_POSIX 0x0004
 
 #define NFS4_SHARE_ACCESS_READ 0x0001
 #define NFS4_SHARE_ACCESS_WRITE        0x0002
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 */
index 2b5ad1b..0682cb9 100644 (file)
@@ -43,6 +43,23 @@ struct parport_pc_private {
        struct parport *port;
 };
 
+struct parport_pc_via_data
+{
+       /* ISA PnP IRQ routing register 1 */
+       u8 via_pci_parport_irq_reg;
+       /* ISA PnP DMA request routing register */
+       u8 via_pci_parport_dma_reg;
+       /* Register and value to enable SuperIO configuration access */
+       u8 via_pci_superio_config_reg;
+       u8 via_pci_superio_config_data;
+       /* SuperIO function register number */
+       u8 viacfg_function;
+       /* parallel port control register number */
+       u8 viacfg_parport_control;
+       /* Parallel port base address register */
+       u8 viacfg_parport_base;
+};
+
 static __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
 {
 #ifdef DEBUG_PARPORT
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 */
index d728e2f..b74b2b6 100644 (file)
@@ -82,8 +82,9 @@ struct pnp_port {
        struct pnp_port *next;          /* next port */
 };
 
+#define PNP_IRQ_NR 256
 struct pnp_irq {
-       unsigned short map;             /* bitmaks for IRQ lines */
+       DECLARE_BITMAP(map, PNP_IRQ_NR); /* bitmaks for IRQ lines */
        unsigned char flags;            /* IRQ flags */
        unsigned char pad;              /* pad */
        struct pnp_irq *next;           /* next IRQ */
@@ -200,6 +201,7 @@ struct pnp_dev {
        unsigned short  regs;           /* ISAPnP: supported registers */
        int             flags;          /* used by protocols */
        struct proc_dir_entry *procent; /* device entry in /proc/bus/isapnp */
+       void *data;
 };
 
 #define global_to_pnp_dev(n) list_entry(n, struct pnp_dev, global_list)
index a22f4a1..026969a 100644 (file)
@@ -53,13 +53,13 @@ int task_handoff_unregister(struct notifier_block * n);
 int profile_event_register(enum profile_type, struct notifier_block * n);
 int profile_event_unregister(enum profile_type, struct notifier_block * n);
 
-int register_profile_notifier(struct notifier_block * nb);
-int unregister_profile_notifier(struct notifier_block * nb);
+int register_timer_hook(int (*hook)(struct pt_regs *));
+void unregister_timer_hook(int (*hook)(struct pt_regs *));
 
-struct pt_regs;
+/* Timer based profiling hook */
+extern int (*timer_hook)(struct pt_regs *);
 
-/* profiling hook activated on each timer interrupt */
-void profile_hook(struct pt_regs * regs);
+struct pt_regs;
 
 #else
 
@@ -87,18 +87,16 @@ static inline int profile_event_unregister(enum profile_type t, struct notifier_
 #define profile_handoff_task(a) (0)
 #define profile_munmap(a) do { } while (0)
 
-static inline int register_profile_notifier(struct notifier_block * nb)
+static inline int register_timer_hook(int (*hook)(struct pt_regs *))
 {
        return -ENOSYS;
 }
 
-static inline int unregister_profile_notifier(struct notifier_block * nb)
+static inline void unregister_timer_hook(int (*hook)(struct pt_regs *))
 {
-       return -ENOSYS;
+       return;
 }
 
-#define profile_hook(regs) do { } while (0)
-
 #endif /* CONFIG_PROFILING */
 
 #endif /* __KERNEL__ */
index fad5699..a6a67d1 100644 (file)
@@ -60,7 +60,7 @@
  */
 #define MD_MAJOR_VERSION                0
 #define MD_MINOR_VERSION                90
-#define MD_PATCHLEVEL_VERSION           0
+#define MD_PATCHLEVEL_VERSION           1
 
 extern int register_md_personality (int p_num, mdk_personality_t *p);
 extern int unregister_md_personality (int p_num);
index 945346e..c9a0d40 100644 (file)
 #define MULTIPATH         7UL
 #define RAID6            8UL
 #define        RAID10            9UL
-#define MAX_PERSONALITY   10UL
+#define FAULTY           10UL
+#define MAX_PERSONALITY   11UL
 
 #define        LEVEL_MULTIPATH         (-4)
 #define        LEVEL_LINEAR            (-1)
+#define        LEVEL_FAULTY            (-5)
 
 #define MaxSector (~(sector_t)0)
 #define MD_THREAD_NAME_MAX 14
@@ -36,6 +38,7 @@
 static inline int pers_to_level (int pers)
 {
        switch (pers) {
+               case FAULTY:            return LEVEL_FAULTY;
                case MULTIPATH:         return LEVEL_MULTIPATH;
                case HSM:               return -3;
                case TRANSLUCENT:       return -2;
@@ -53,6 +56,7 @@ static inline int pers_to_level (int pers)
 static inline int level_to_pers (int level)
 {
        switch (level) {
+               case LEVEL_FAULTY: return FAULTY;
                case LEVEL_MULTIPATH: return MULTIPATH;
                case -3: return HSM;
                case -2: return TRANSLUCENT;
@@ -290,6 +294,7 @@ struct mdk_personality_s
        int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster);
        int (*resize) (mddev_t *mddev, sector_t sectors);
        int (*reshape) (mddev_t *mddev, int raid_disks);
+       int (*reconfig) (mddev_t *mddev, int layout, int chunk_size);
 };
 
 
index 022b607..8ba95d6 100644 (file)
@@ -197,7 +197,7 @@ struct mdp_superblock_1 {
 
        __u32   chunksize;      /* in 512byte sectors */
        __u32   raid_disks;
-       __u8    pad1[128-92];   /* set to 0 when written */
+       __u8    pad1[128-96];   /* set to 0 when written */
 
        /* constant this-device information - 64 bytes */
        __u64   data_offset;    /* sector start of data, often 0 */
@@ -215,7 +215,7 @@ struct mdp_superblock_1 {
        __u64   resync_offset;  /* data before this offset (from data_offset) known to be in sync */
        __u32   sb_csum;        /* checksum upto devs[max_dev] */
        __u32   max_dev;        /* size of devs[] array to consider */
-       __u8    pad3[64-40];    /* set to 0 when writing */
+       __u8    pad3[64-32];    /* set to 0 when writing */
 
        /* device state information. Indexed by dev_number.
         * 2 bytes per device
index a8db266..6f53fc1 100644 (file)
@@ -13,6 +13,7 @@ struct multipath_private_data {
        int                     raid_disks;
        int                     working_disks;
        spinlock_t              device_lock;
+       struct list_head        retry_list;
 
        mempool_t               *pool;
 };
@@ -36,6 +37,6 @@ struct multipath_bh {
        struct bio              *master_bio;
        struct bio              bio;
        int                     path;
-       struct multipath_bh     *next_mp; /* next for retry */
+       struct list_head        retry_list;
 };
 #endif
index 50965d9..abbfdd9 100644 (file)
@@ -35,6 +35,7 @@ struct r1_private_data_s {
        sector_t                next_seq_sect;
        spinlock_t              device_lock;
 
+       struct list_head        retry_list;
        /* for use when syncing mirrors: */
 
        spinlock_t              resync_lock;
index 3ae0c6e..4b7cc4f 100644 (file)
@@ -113,8 +113,7 @@ struct rb_root
 };
 
 #define RB_ROOT        (struct rb_root) { NULL, }
-#define        rb_entry(ptr, type, member)                                     \
-       ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+#define        rb_entry(ptr, type, member) container_of(ptr, type, member)
 
 extern void rb_insert_color(struct rb_node *, struct rb_root *);
 extern void rb_erase(struct rb_node *, struct rb_root *);
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 */
index cff2834..1ed3da0 100644 (file)
@@ -281,7 +281,11 @@ typedef struct sctp_ecn_capable_param {
        sctp_paramhdr_t param_hdr;
 } __attribute__((packed)) sctp_ecn_capable_param_t;
 
-
+/* ADDIP Section 3.2.6 Adaption Layer Indication */
+typedef struct sctp_adaption_ind_param {
+       struct sctp_paramhdr param_hdr;
+       __u32 adaption_ind;
+} __attribute__((packed)) sctp_adaption_ind_param_t;
 
 /* RFC 2960.  Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2):
  *   The INIT ACK chunk is used to acknowledge the initiation of an SCTP
index 9a07d00..0014582 100644 (file)
@@ -181,6 +181,8 @@ extern void unregister_serial(int line);
 /* Allow architectures to override entries in serial8250_ports[] at run time: */
 struct uart_port;      /* forward declaration */
 extern int early_serial_setup(struct uart_port *port);
+extern int early_serial_console_init(char *options);
+extern int serial8250_start_console(struct uart_port *port, char *options);
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SERIAL_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
index 7b2414b..faa0c36 100644 (file)
 #ifndef _LINUX_SERIAL_REG_H
 #define _LINUX_SERIAL_REG_H
 
-#define UART_RX                0       /* In:  Receive buffer (DLAB=0) */
-#define UART_TX                0       /* 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 */
+/*
+ * DLAB=0
+ */
+#define UART_RX                0       /* In:  Receive buffer */
+#define UART_TX                0       /* Out: Transmit buffer */
 
-#define UART_DLM       1       /* Out: Divisor Latch High (DLAB=1) */
 #define UART_IER       1       /* Out: Interrupt Enable Register */
-#define UART_FCTR      1       /* (LCR=BF) Feature Control Register
-                                * XR16C85x only */
+#define UART_IER_MSI           0x08 /* Enable Modem status interrupt */
+#define UART_IER_RLSI          0x04 /* Enable receiver line status interrupt */
+#define UART_IER_THRI          0x02 /* Enable Transmitter holding register int. */
+#define UART_IER_RDI           0x01 /* Enable receiver data interrupt */
+/*
+ * Sleep mode for ST16650 and TI16750.  For the ST16650, EFR[4]=1
+ */
+#define UART_IERX_SLEEP                0x10 /* Enable sleep mode */
 
 #define UART_IIR       2       /* In:  Interrupt ID Register */
-#define UART_FCR       2       /* Out: FIFO Control Register */
-#define UART_EFR       2       /* I/O: Extended Features Register */
-                               /* (DLAB=1, 16C660 only) */
+#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 */
 
-#define UART_LCR       3       /* Out: Line Control Register */
-#define UART_MCR       4       /* Out: Modem Control Register */
-#define UART_LSR       5       /* In:  Line Status Register */
-#define UART_MSR       6       /* In:  Modem Status Register */
-#define UART_SCR       7       /* I/O: Scratch Register */
-#define UART_EMSR      7       /* (LCR=BF) Extended Mode Select Register 
-                                * FCTR bit 6 selects SCR or EMSR
-                                * XR16c85x only */
-
-/*
- * These are the definitions for the FIFO Control Register
- * (16650 only)
- */
+#define UART_FCR       2       /* Out: FIFO Control Register */
 #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 */
+/*
+ * Note: The FIFO trigger levels are chip specific:
+ *     RX:76 = 00  01  10  11  TX:54 = 00  01  10  11
+ * PC16550D:    1   4   8  14          xx  xx  xx  xx
+ * TI16C550A:   1   4   8  14          xx  xx  xx  xx
+ * TI16C550C:   1   4   8  14          xx  xx  xx  xx
+ * ST16C550:    1   4   8  14          xx  xx  xx  xx
+ * ST16C650:    8  16  24  28          16   8  24  30  PORT_16650V2
+ * NS16C552:    1   4   8  14          xx  xx  xx  xx
+ * ST16C654:    8  16  56  60           8  16  32  56  PORT_16654
+ * TI16C750:    1  16  32  56          xx  xx  xx  xx  PORT_16750
+ * TI16C752:    8  16  56  60           8  16  32  56
+ */
+#define UART_FCR_R_TRIG_00     0x00
+#define UART_FCR_R_TRIG_01     0x40
+#define UART_FCR_R_TRIG_10     0x80
+#define UART_FCR_R_TRIG_11     0xc0
+#define UART_FCR_T_TRIG_00     0x00
+#define UART_FCR_T_TRIG_01     0x10
+#define UART_FCR_T_TRIG_10     0x20
+#define UART_FCR_T_TRIG_11     0x30
+
 #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 */
+/* 16650 definitions */
 #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_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 */
+#define UART_FCR7_64BYTE       0x20 /* Go into 64 byte mode (TI16C750) */
 
+#define UART_LCR       3       /* Out: Line Control Register */
 /*
- * 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 */
+#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 bit, 1=2 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 */
+
+#define UART_MCR       4       /* Out: Modem Control Register */
+#define UART_MCR_CLKSEL                0x80 /* Divide clock by 4 (TI16C752, EFR[4]=1) */
+#define UART_MCR_TCRTLR                0x40 /* Access TCR/TLR (TI16C752, EFR[4]=1) */
+#define UART_MCR_XONANY                0x20 /* Enable Xon Any (TI16C752, EFR[4]=1) */
+#define UART_MCR_AFE           0x20 /* Enable auto-RTS/CTS (TI16C550C/TI16C750) */
+#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 */
+
+#define UART_LSR       5       /* In:  Line Status Register */
+#define UART_LSR_TEMT          0x40 /* Transmitter empty */
+#define UART_LSR_THRE          0x20 /* Transmit-hold-register empty */
+#define UART_LSR_BI            0x10 /* Break interrupt indicator */
+#define UART_LSR_FE            0x08 /* Frame error indicator */
+#define UART_LSR_PE            0x04 /* Parity error indicator */
+#define UART_LSR_OE            0x02 /* Overrun error indicator */
+#define UART_LSR_DR            0x01 /* Receiver data ready */
+
+#define UART_MSR       6       /* In:  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! */
+
+#define UART_SCR       7       /* I/O: Scratch Register */
 
 /*
- * These are the definitions for the Line Status Register
+ * DLAB=1
  */
-#define UART_LSR_TEMT  0x40    /* Transmitter empty */
-#define UART_LSR_THRE  0x20    /* Transmit-hold-register empty */
-#define UART_LSR_BI    0x10    /* Break interrupt indicator */
-#define UART_LSR_FE    0x08    /* Frame error indicator */
-#define UART_LSR_PE    0x04    /* Parity error indicator */
-#define UART_LSR_OE    0x02    /* Overrun error indicator */
-#define UART_LSR_DR    0x01    /* Receiver data ready */
+#define UART_DLL       0       /* Out: Divisor Latch Low */
+#define UART_DLM       1       /* Out: Divisor Latch High */
 
 /*
- * These are the definitions for the Interrupt Identification Register
+ * LCR=0xBF (or DLAB=1 for 16C660)
+ */
+#define UART_EFR       2       /* I/O: Extended Features Register */
+#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
  */
-#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
+ * LCR=0xBF, TI16C752, ST16650, ST16650A, ST16654
  */
-#define UART_IER_MSI   0x08    /* Enable Modem status interrupt */
-#define UART_IER_RLSI  0x04    /* Enable receiver line status interrupt */
-#define UART_IER_THRI  0x02    /* Enable Transmitter holding register int. */
-#define UART_IER_RDI   0x01    /* Enable receiver data interrupt */
+#define UART_XON1      4       /* I/O: Xon character 1 */
+#define UART_XON2      5       /* I/O: Xon character 2 */
+#define UART_XOFF1     6       /* I/O: Xoff character 1 */
+#define UART_XOFF2     7       /* I/O: Xoff character 2 */
+
 /*
- * Sleep mode for ST16650 and TI16750.
- * Note that for 16650, EFR-bit 4 must be selected as well.
+ * EFR[4]=1 MCR[6]=1, TI16C752
  */
-#define UART_IERX_SLEEP  0x10  /* Enable sleep mode */
+#define UART_TI752_TCR 6       /* I/O: transmission control register */
+#define UART_TI752_TLR 7       /* I/O: trigger level register */
 
 /*
- * These are the definitions for the Modem Control Register
+ * LCR=0xBF, XR16C85x
  */
-#define UART_MCR_AFE   0x20    /* Enable auto-RTS/CTS (TI16C750) */
-#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 */
+#define UART_TRG       0       /* FCTR bit 7 selects Rx or Tx
+                                * In: Fifo count
+                                * Out: Fifo custom trigger levels */
+/*
+ * These are the definitions for the Programmable Trigger Register
+ */
+#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
+
+#define UART_FCTR      1       /* Feature Control Register */
+#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 Modem Status Register
+ * LCR=0xBF, FCTR[6]=1
  */
-#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! */
+#define UART_EMSR      7       /* Extended Mode Select Register */
+#define UART_EMSR_FIFO_COUNT   0x01  /* Rx/Tx select */
+#define UART_EMSR_ALT_COUNT    0x02  /* Alternating count select */
 
 /*
  * The Intel XScale on-chip UARTs define these bits
 #define UART_FCR_PXAR16        0x80    /* receive FIFO treshold = 16 */
 #define UART_FCR_PXAR32        0xc0    /* receive FIFO treshold = 32 */
 
-/*
- * 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_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
index c776bcd..c415312 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/smb.h>
 #include <linux/smb_fs_i.h>
 #include <linux/smb_fs_sb.h>
-#include <linux/fs.h>
 
 /*
  * ioctl commands
@@ -26,6 +25,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
 #include <linux/smb_mount.h>
index 256900c..d10f00c 100644 (file)
@@ -38,7 +38,10 @@ struct smb_mount_data {
 #define SMB_MOUNT_DIRATTR      0x0004  /* Use find_first for getattr */
 #define SMB_MOUNT_CASE         0x0008  /* Be case sensitive */
 #define SMB_MOUNT_UNICODE      0x0010  /* Server talks unicode */
-
+#define SMB_MOUNT_UID          0x0020  /* Use user specified uid */
+#define SMB_MOUNT_GID          0x0040  /* Use user specified gid */
+#define SMB_MOUNT_FMODE                0x0080  /* Use user specified file mode */
+#define SMB_MOUNT_DMODE                0x0100  /* Use user specified dir mode */
 
 struct smb_mount_data_kernel {
        int version;
index 1ad9711..388d573 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * Sony Programmable I/O Control Device driver for VAIO
  *
- * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+ * Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
  *
  * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
  * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the 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 _SONYPI_H_ 
+#ifndef _SONYPI_H_
 #define _SONYPI_H_
 
 #include <linux/types.h>
@@ -96,6 +96,7 @@
 #define SONYPI_EVENT_ANYBUTTON_RELEASED                56
 #define SONYPI_EVENT_BATTERY_INSERT            57
 #define SONYPI_EVENT_BATTERY_REMOVE            58
+#define SONYPI_EVENT_FNKEY_RELEASED            59
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT         _IOR('v', 0, __u8)
 
 /* used only for communication between v4l and sonypi */
 
-#define SONYPI_COMMAND_GETCAMERA                1
+#define SONYPI_COMMAND_GETCAMERA                1      /* obsolete */
 #define SONYPI_COMMAND_SETCAMERA                2
-#define SONYPI_COMMAND_GETCAMERABRIGHTNESS      3
+#define SONYPI_COMMAND_GETCAMERABRIGHTNESS      3      /* obsolete */
 #define SONYPI_COMMAND_SETCAMERABRIGHTNESS      4
-#define SONYPI_COMMAND_GETCAMERACONTRAST        5
+#define SONYPI_COMMAND_GETCAMERACONTRAST        5      /* obsolete */
 #define SONYPI_COMMAND_SETCAMERACONTRAST        6
-#define SONYPI_COMMAND_GETCAMERAHUE             7
+#define SONYPI_COMMAND_GETCAMERAHUE             7      /* obsolete */
 #define SONYPI_COMMAND_SETCAMERAHUE             8
-#define SONYPI_COMMAND_GETCAMERACOLOR           9
+#define SONYPI_COMMAND_GETCAMERACOLOR           9      /* obsolete */
 #define SONYPI_COMMAND_SETCAMERACOLOR          10
-#define SONYPI_COMMAND_GETCAMERASHARPNESS      11
+#define SONYPI_COMMAND_GETCAMERASHARPNESS      11      /* obsolete */
 #define SONYPI_COMMAND_SETCAMERASHARPNESS      12
-#define SONYPI_COMMAND_GETCAMERAPICTURE                13
+#define SONYPI_COMMAND_GETCAMERAPICTURE                13      /* obsolete */
 #define SONYPI_COMMAND_SETCAMERAPICTURE                14
-#define SONYPI_COMMAND_GETCAMERAAGC            15
+#define SONYPI_COMMAND_GETCAMERAAGC            15      /* obsolete */
 #define SONYPI_COMMAND_SETCAMERAAGC            16
-#define SONYPI_COMMAND_GETCAMERADIRECTION      17
-#define SONYPI_COMMAND_GETCAMERAROMVERSION     18
-#define SONYPI_COMMAND_GETCAMERAREVISION       19
+#define SONYPI_COMMAND_GETCAMERADIRECTION      17      /* obsolete */
+#define SONYPI_COMMAND_GETCAMERAROMVERSION     18      /* obsolete */
+#define SONYPI_COMMAND_GETCAMERAREVISION       19      /* obsolete */
 
-u8 sonypi_camera_command(int command, u8 value);
+int sonypi_camera_command(int command, u8 value);
 
-#endif /* __KERNEL__ */
+#endif                         /* __KERNEL__ */
 
-#endif /* _SONYPI_H_ */
+#endif                         /* _SONYPI_H_ */
index 0cfc704..d4c7db3 100644 (file)
@@ -30,8 +30,7 @@ static inline swp_entry_t swp_entry(unsigned long type, pgoff_t offset)
  */
 static inline unsigned swp_type(swp_entry_t entry)
 {
-       return (entry.val >> SWP_TYPE_SHIFT(entry)) &
-                       ((1 << MAX_SWAPFILES_SHIFT) - 1);
+       return (entry.val >> SWP_TYPE_SHIFT(entry));
 }
 
 /*
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
index 047e28b..4243c55 100644 (file)
@@ -30,6 +30,6 @@
 /*
  * A maximum of 4 million PIDs should be enough for a while:
  */
-#define PID_MAX_LIMIT (4*1024*1024)
+#define PID_MAX_LIMIT (sizeof(long) > 4 ? 4*1024*1024 : PID_MAX_DEFAULT)
 
 #endif
index 5aa24b4..8c22120 100644 (file)
@@ -38,5 +38,7 @@
 #define IOCTL_TIUSB_TIMEOUT        _IOW('N', 0x20, int) /* set timeout */
 #define IOCTL_TIUSB_RESET_DEVICE   _IOW('N', 0x21, int) /* reset device */
 #define IOCTL_TIUSB_RESET_PIPES    _IOW('N', 0x22, int) /* reset both pipes*/
+#define IOCTL_TIUSB_GET_MAXPS      _IOR('N', 0x23, int) /* max packet size */
+#define IOCTL_TIUSB_GET_DEVID      _IOR('N', 0x24, int) /* get device type */
 
 #endif /* TICABLE_H */
index fbaa877..10df254 100644 (file)
@@ -61,4 +61,76 @@ static inline int __next_node_with_cpus(int node)
 #define PENALTY_FOR_NODE_WITH_CPUS     (1)
 #endif
 
+/*
+ * Below are the 3 major initializers used in building sched_domains:
+ * SD_SIBLING_INIT, for SMT domains
+ * SD_CPU_INIT, for SMP domains
+ * SD_NODE_INIT, for NUMA domains
+ *
+ * Any architecture that cares to do any tuning to these values should do so
+ * by defining their own arch-specific initializer in include/asm/topology.h.
+ * A definition there will automagically override these default initializers
+ * and allow arch-specific performance tuning of sched_domains.
+ */
+#ifdef CONFIG_SCHED_SMT
+/* MCD - Do we really need this?  It is always on if CONFIG_SCHED_SMT is,
+ * so can't we drop this in favor of CONFIG_SCHED_SMT?
+ */
+#define ARCH_HAS_SCHED_WAKE_IDLE
+/* Common values for SMT siblings */
+#ifndef SD_SIBLING_INIT
+#define SD_SIBLING_INIT (struct sched_domain) {                \
+       .span                   = CPU_MASK_NONE,        \
+       .parent                 = NULL,                 \
+       .groups                 = NULL,                 \
+       .min_interval           = 1,                    \
+       .max_interval           = 2,                    \
+       .busy_factor            = 8,                    \
+       .imbalance_pct          = 110,                  \
+       .cache_hot_time         = 0,                    \
+       .cache_nice_tries       = 0,                    \
+       .per_cpu_gain           = 25,                   \
+       .flags                  = SD_LOAD_BALANCE       \
+                               | SD_BALANCE_NEWIDLE    \
+                               | SD_BALANCE_EXEC       \
+                               | SD_WAKE_AFFINE        \
+                               | SD_WAKE_IDLE          \
+                               | SD_SHARE_CPUPOWER,    \
+       .last_balance           = jiffies,              \
+       .balance_interval       = 1,                    \
+       .nr_balance_failed      = 0,                    \
+}
+#endif
+#endif /* CONFIG_SCHED_SMT */
+
+/* Common values for CPUs */
+#ifndef SD_CPU_INIT
+#define SD_CPU_INIT (struct sched_domain) {            \
+       .span                   = CPU_MASK_NONE,        \
+       .parent                 = NULL,                 \
+       .groups                 = NULL,                 \
+       .min_interval           = 1,                    \
+       .max_interval           = 4,                    \
+       .busy_factor            = 64,                   \
+       .imbalance_pct          = 125,                  \
+       .cache_hot_time         = (5*1000/2),           \
+       .cache_nice_tries       = 1,                    \
+       .per_cpu_gain           = 100,                  \
+       .flags                  = SD_LOAD_BALANCE       \
+                               | SD_BALANCE_NEWIDLE    \
+                               | SD_BALANCE_EXEC       \
+                               | SD_WAKE_AFFINE        \
+                               | SD_WAKE_BALANCE,      \
+       .last_balance           = jiffies,              \
+       .balance_interval       = 1,                    \
+       .nr_balance_failed      = 0,                    \
+}
+#endif
+
+#ifdef CONFIG_NUMA
+#ifndef SD_NODE_INIT
+#error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
+#endif
+#endif /* CONFIG_NUMA */
+
 #endif /* _LINUX_TOPOLOGY_H */
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
index 8022bf1..2f51f2b 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :   16      2.4.03
+ * Version :   17      21.6.04
  *
  * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _LINUX_WIRELESS_H
  *     # include/net/iw_handler.h
  *
  * Note as well that /proc/net/wireless implementation has now moved in :
- *     # include/linux/wireless.c
+ *     # net/core/wireless.c
  *
  * Wireless Events (2002 -> onward) :
  * --------------------------------
  * Events are defined at the end of this file, and implemented in :
- *     # include/linux/wireless.c
+ *     # net/core/wireless.c
  *
  * Other comments :
  * --------------
@@ -82,7 +82,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT   16
+#define WIRELESS_EXT   17
 
 /*
  * Changes :
  *     - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
  *     - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
  *     - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
+ *
+ * V16 to V17
+ * ----------
+ *     - Add flags to frequency -> auto/fixed
+ *     - Document (struct iw_quality *)->updated, add new flags (INVALID)
+ *     - Wireless Event capability in struct iw_range
+ *     - Add support for relative TxPower (yick !)
  */
 
 /**************************** CONSTANTS ****************************/
 
 /* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
 
-/* These 16 ioctl are wireless device private.
+/* These 32 ioctl are wireless device private, for 16 commands.
  * Each driver is free to use them for whatever purpose it chooses,
  * however the driver *must* export the description of those ioctls
  * with SIOCGIWPRIV and *must* use arguments as defined below.
  * We now have 32 commands, so a bit more space ;-).
  * Also, all 'odd' commands are only usable by root and don't return the
  * content of ifr/iwr to user (but you are not obliged to use the set/get
- * convention, just use every other two command).
- * And I repeat : you are not obliged to use them with iwspy, but you
+ * convention, just use every other two command). More details in iwpriv.c.
+ * And I repeat : you are not forced to use them with iwpriv, but you
  * must be compliant with it.
  */
 
 #define IW_MODE_SECOND 5       /* Secondary master/repeater (backup) */
 #define IW_MODE_MONITOR        6       /* Passive monitor (listen only) */
 
+/* Statistics flags (bitmask in updated) */
+#define IW_QUAL_QUAL_UPDATED   0x1     /* Value was updated since last read */
+#define IW_QUAL_LEVEL_UPDATED  0x2
+#define IW_QUAL_NOISE_UPDATED  0x4
+#define IW_QUAL_QUAL_INVALID   0x10    /* Driver doesn't provide value */
+#define IW_QUAL_LEVEL_INVALID  0x20
+#define IW_QUAL_NOISE_INVALID  0x40
+
+/* Frequency flags */
+#define IW_FREQ_AUTO           0x00    /* Let the driver decides */
+#define IW_FREQ_FIXED          0x01    /* Force a specific value */
+
 /* Maximum number of size of encoding token available
  * they are listed in the range structure */
 #define IW_MAX_ENCODING_SIZES  8
 #define IW_TXPOW_TYPE          0x00FF  /* Type of value */
 #define IW_TXPOW_DBM           0x0000  /* Value is in dBm */
 #define IW_TXPOW_MWATT         0x0001  /* Value is in mW */
+#define IW_TXPOW_RELATIVE      0x0002  /* Value is in arbitrary units */
 #define IW_TXPOW_RANGE         0x1000  /* Range of value between min/max */
 
 /* Retry limits and lifetime flags available */
 /* Max number of char in custom event - use multiple of them if needed */
 #define IW_CUSTOM_MAX          256     /* In bytes */
 
+/* Event capability macros - in (struct iw_range *)->event_capa
+ * Because we have more than 32 possible events, we use an array of
+ * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
+#define IW_EVENT_CAPA_BASE(cmd)                ((cmd >= SIOCIWFIRSTPRIV) ? \
+                                        (cmd - SIOCIWFIRSTPRIV + 0x60) : \
+                                        (cmd - SIOCSIWCOMMIT))
+#define IW_EVENT_CAPA_INDEX(cmd)       (IW_EVENT_CAPA_BASE(cmd) >> 5)
+#define IW_EVENT_CAPA_MASK(cmd)                (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
+/* Event capability constants - event autogenerated by the kernel
+ * This list is valid for most 802.11 devices, customise as needed... */
+#define IW_EVENT_CAPA_K_0      (IW_EVENT_CAPA_MASK(0x8B04) | \
+                                IW_EVENT_CAPA_MASK(0x8B06) | \
+                                IW_EVENT_CAPA_MASK(0x8B1A))
+#define IW_EVENT_CAPA_K_1      (IW_EVENT_CAPA_MASK(0x8B2A))
+/* "Easy" macro to set events in iw_range (less efficient) */
+#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
+#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
+
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -456,7 +495,7 @@ struct      iw_freq
        __s32           m;              /* Mantissa */
        __s16           e;              /* Exponent */
        __u8            i;              /* List index (when in range struct) */
-       __u8            pad;            /* Unused - just for alignement */
+       __u8            flags;          /* Flags (fixed/auto) */
 };
 
 /*
@@ -610,11 +649,12 @@ struct    iw_range
        /* Old Frequency (backward compat - moved lower ) */
        __u16           old_num_channels;
        __u8            old_num_frequency;
-       /* Filler to keep "version" at the same offset */
-       __s32           old_freq[6];
+
+       /* Wireless event capability bitmasks */
+       __u32           event_capa[6];
 
        /* signal level threshold range */
-       __s32   sensitivity;
+       __s32           sensitivity;
 
        /* Quality of link & SNR stuff */
        /* Quality range (link, level, noise)
index fadc32d..d3e9e30 100644 (file)
@@ -13,7 +13,7 @@
 #define AUDIO_RADIO        0x01
 #define AUDIO_EXTERN       0x02
 #define AUDIO_INTERN       0x03
-#define AUDIO_OFF          0x04 
+#define AUDIO_OFF          0x04
 #define AUDIO_ON           0x05
 #define AUDIO_EXTERN_1     AUDIO_EXTERN
 #define AUDIO_EXTERN_2     0x06
index 8485d2e..135f9a6 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
     saa6752hs.h - definition for saa6752hs MPEG encoder
 
     Copyright (C) 2003 Andrew de Quincey <adq@lidskialf.net>
@@ -31,14 +31,14 @@ enum mpeg_bitrate_mode {
 enum mpeg_audio_bitrate {
        MPEG_AUDIO_BITRATE_256 = 0, /* 256 kBit/sec */
        MPEG_AUDIO_BITRATE_384 = 1, /* 384 kBit/sec */
-    
+
        MPEG_AUDIO_BITRATE_MAX
 };
 
 #define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
 #define MPEG_VIDEO_MAX_BITRATE_MAX 27000
 #define MPEG_TOTAL_BITRATE_MAX 27000
-    
+
 struct mpeg_params {
        enum mpeg_bitrate_mode bitrate_mode;
        unsigned int video_target_bitrate;
index e62f03f..171dbb6 100644 (file)
@@ -51,10 +51,12 @@ extern unsigned int saa7146_debug;
 #define DEB_INT(x)  if (0!=(DEBUG_VARIABLE&0x20)) { DEBUG_PROLOG; printk x; } /* interrupt debug messages */
 #define DEB_CAP(x)  if (0!=(DEBUG_VARIABLE&0x40)) { DEBUG_PROLOG; printk x; } /* capture debug messages */
 
-#define IER_DISABLE(x,y) \
+#define SAA7146_IER_DISABLE(x,y) \
        saa7146_write(x, IER, saa7146_read(x, IER) & ~(y));
-#define IER_ENABLE(x,y) \
+#define SAA7146_IER_ENABLE(x,y) \
        saa7146_write(x, IER, saa7146_read(x, IER) | (y));
+#define SAA7146_ISR_CLEAR(x,y) \
+       saa7146_write(x, ISR, (y));
 
 struct saa7146_dev;
 struct saa7146_extension;
@@ -123,7 +125,7 @@ struct saa7146_dev
                spinlock_t                      slock;
         struct semaphore               lock;
 
-       unsigned char                   *mem;           /* pointer to mapped IO memory */
+       unsigned char                   __iomem *mem;   /* pointer to mapped IO memory */
        int                             revision;       /* chip revision; needed for bug-workarounds*/
 
        /* pci-device & irq stuff*/
@@ -154,7 +156,7 @@ struct saa7146_dev
 };
 
 /* from saa7146_i2c.c */
-int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, unsigned int class, u32 bitrate);
+int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
 int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg msgs[], int num,  int retries);
 
 /* from saa7146_core.c */
@@ -168,7 +170,7 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
 int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
 char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
 void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
-int saa7146_wait_for_debi_done(struct saa7146_dev *dev);
+int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
 
 /* some memory sizes */
 #define SAA7146_I2C_MEM                ( 1*PAGE_SIZE)
index 9597ffe..3b91bb6 100644 (file)
@@ -1,4 +1,5 @@
-/* 
+
+/*
     tuner.h - definition for different tuners
 
     Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
 #define TUNER_PHILIPS_ATSC       42
 #define TUNER_PHILIPS_FM1236_MK3 43
 #define TUNER_PHILIPS_4IN1       44    /* ATI TV Wonder Pro - Conexant */
+/* Microtune mergeged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */
 #define TUNER_MICROTUNE_4049FM5  45
 #define TUNER_LG_NTSC_TAPE       47
 #define TUNER_TNF_8831BGFF       48
+#define TUNER_MICROTUNE_4042FI5  49    /* FusionHDTV 3 Gold - 4042 FI5 (3X 8147) */
+#define TUNER_TCL_2002N          50
+#define TUNER_PHILIPS_FM1256_IH3   51
 
 #define NOTUNER 0
 #define PAL     1      /* PAL_BG */
@@ -91,6 +96,7 @@
 #define Microtune 8
 #define HITACHI 9
 #define Panasonic 10
+#define TCL     11
 
 #define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
 #define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
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:
+ */
index e872ad7..db93b7b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtd-abi.h,v 1.5 2004/06/22 09:29:35 gleixner Exp $
+ * $Id: mtd-abi.h,v 1.6 2004/08/09 13:38:30 dwmw2 Exp $
  *
  * Portions of MTD ABI definition which are shared by kernel and user space 
  */
@@ -7,6 +7,11 @@
 #ifndef __MTD_ABI_H__
 #define __MTD_ABI_H__
 
+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into
+                   separate files was to avoid #ifdef __KERNEL__ */
+#define __user
+#endif
+
 struct erase_info_user {
        uint32_t start;
        uint32_t length;
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
index 646dea8..6bbeafa 100644 (file)
@@ -37,7 +37,7 @@ extern int dn_nsp_rx(struct sk_buff *);
 extern int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 
 extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri);
-extern struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, int *err);
+extern struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, long timeo, int *err);
 
 #define NSP_REASON_OK 0                /* No error */
 #define NSP_REASON_NR 1                /* No resources */
index e3ec2eb..9a9bea5 100644 (file)
@@ -41,5 +41,8 @@ extern int gen_new_estimator(struct gnet_stats_basic *bstats,
                             spinlock_t *stats_lock, struct rtattr *opt);
 extern void gen_kill_estimator(struct gnet_stats_basic *bstats,
                               struct gnet_stats_rate_est *rate_est);
+extern int gen_replace_estimator(struct gnet_stats_basic *bstats,
+                                struct gnet_stats_rate_est *rate_est,
+                                spinlock_t *stats_lock, struct rtattr *opt);
 
 #endif
index 9ba2479..7fee4c0 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <asm/types.h>         /* For __uXX types */
 
-#define IP_VS_VERSION_CODE     0x010200
+#define IP_VS_VERSION_CODE     0x010201
 #define NVERSION(version)                      \
        (version >> 16) & 0xFF,                 \
        (version >> 8) & 0xFF,                  \
@@ -358,6 +358,7 @@ enum {
        NET_IPV4_VS_EXPIRE_NODEST_CONN=23,
        NET_IPV4_VS_SYNC_THRESHOLD=24,
        NET_IPV4_VS_NAT_ICMP_SEND=25,
+       NET_IPV4_VS_EXPIRE_QUIESCENT_TEMPLATE=26,
        NET_IPV4_VS_LAST
 };
 
@@ -879,6 +880,7 @@ extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
  */
 extern int sysctl_ip_vs_cache_bypass;
 extern int sysctl_ip_vs_expire_nodest_conn;
+extern int sysctl_ip_vs_expire_quiescent_template;
 extern int sysctl_ip_vs_sync_threshold[2];
 extern int sysctl_ip_vs_nat_icmp_send;
 extern struct ip_vs_stats ip_vs_stats;
index 357bf08..7f46561 100644 (file)
@@ -72,7 +72,6 @@ extern char *ircomm_tty_state[];
 
 int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
                        struct sk_buff *skb, struct ircomm_tty_info *info);
-void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state);
 
 
 int  ircomm_tty_attach_cable(struct ircomm_tty_cb *self);
index 6ffaed3..c41196b 100644 (file)
@@ -81,7 +81,8 @@ struct ias_attrib {
 struct ias_object *irias_new_object(char *name, int id);
 void irias_insert_object(struct ias_object *obj);
 int  irias_delete_object(struct ias_object *obj);
-int  irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib);
+int  irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib,
+                        int cleanobject);
 void __irias_delete_object(struct ias_object *obj);
 
 void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
index 9d24d6c..2c5d886 100644 (file)
@@ -58,14 +58,16 @@ struct lap_cb;
  *  Slot timer must never exceed 85 ms, and must always be at least 25 ms, 
  *  suggested to  75-85 msec by IrDA lite. This doesn't work with a lot of
  *  devices, and other stackes uses a lot more, so it's best we do it as well
+ *  (Note : this is the default value and sysctl overides it - Jean II)
  */
 #define SLOT_TIMEOUT            (90*HZ/1000)
 
 /* 
- *  We set the query timeout to 100 ms and then expect the value to be 
- *  multiplied with the number of slots to product the actual timeout value
+ *  The latest discovery frame (XID) is longer due to the extra discovery
+ *  information (hints, device name...). This is its extra length.
+ *  We use that when setting the query timeout. Jean II
  */
-#define QUERY_TIMEOUT           (HZ/10)       
+#define XIDEXTRA_TIMEOUT        (34*HZ/1000)  /* 34 msec */
 
 #define WATCHDOG_TIMEOUT        (20*HZ)       /* 20 sec */
 
@@ -85,7 +87,7 @@ static inline void irda_start_timer(struct timer_list *ptimer, int timeout,
 
 
 void irlap_start_slot_timer(struct irlap_cb *self, int timeout);
-void irlap_start_query_timer(struct irlap_cb *self, int timeout);
+void irlap_start_query_timer(struct irlap_cb *self, int S, int s);
 void irlap_start_final_timer(struct irlap_cb *self, int timeout);
 void irlap_start_wd_timer(struct irlap_cb *self, int timeout);
 void irlap_start_backoff_timer(struct irlap_cb *self, int timeout);
index 5e70aed..ac5acfc 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :   5       4.12.02
+ * Version :   6       21.6.04
  *
  * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 2001-2004 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _IW_HANDLER_H
 /***************************** INCLUDES *****************************/
 
 #include <linux/wireless.h>            /* IOCTL user space API */
+#include <linux/if_ether.h>
 
 /***************************** VERSION *****************************/
 /*
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION     5
+#define IW_HANDLER_VERSION     6
 
 /*
  * Changes :
  * V4 to V5
  * --------
  *     - Add new spy support : struct iw_spy_data & prototypes
+ *
+ * V5 to V6
+ * --------
+ *     - Change the way we get to spy_data method for added safety
+ *     - Remove spy #ifdef, they are always on -> cleaner code
+ *     - Add IW_DESCR_FLAG_NOMAX flag for very large requests
+ *     - Start migrating get_wireless_stats to struct iw_handler_def
  */
 
 /**************************** CONSTANTS ****************************/
 
-/* Enable enhanced spy support. Disable to reduce footprint */
+/* Enhanced spy support available */
 #define IW_WIRELESS_SPY
 #define IW_WIRELESS_THRSPY
 
 #define IW_DESCR_FLAG_EVENT    0x0002  /* Generate an event on SET */
 #define IW_DESCR_FLAG_RESTRICT 0x0004  /* GET : request is ROOT only */
                                /* SET : Omit payload from generated iwevent */
+#define IW_DESCR_FLAG_NOMAX    0x0008  /* GET : no limit on request size */
 /* Driver level flags */
 #define IW_DESCR_FLAG_WAIT     0x0100  /* Wait for driver event */
 
@@ -286,6 +295,8 @@ struct iw_request_info
        __u16           flags;          /* More to come ;-) */
 };
 
+struct net_device;
+
 /*
  * This is how a function handling a Wireless Extension should look
  * like (both get and set, standard and private).
@@ -311,23 +322,25 @@ struct iw_handler_def
        /* Array of handlers for standard ioctls
         * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
         */
-       iw_handler *            standard;
+       const iw_handler *      standard;
 
        /* Array of handlers for private ioctls
         * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
         */
-       iw_handler *            private;
+       const iw_handler *      private;
 
        /* Arguments of private handler. This one is just a list, so you
         * can put it in any order you want and should not leave holes...
         * We will automatically export that to user space... */
-       struct iw_priv_args *   private_args;
+       const struct iw_priv_args *     private_args;
 
-       /* Driver enhanced spy support */
-       long                    spy_offset;     /* Spy data offset */
+       /* This field will be *removed* in the next version of WE */
+       long                    spy_offset;     /* DO NOT USE */
 
-       /* In the long term, get_wireless_stats will move from
-        * 'struct net_device' to here, to minimise bloat. */
+       /* New location of get_wireless_stats, to de-bloat struct net_device.
+        * The old pointer in struct net_device will be gradually phased
+        * out, and drivers are encouraged to use this one... */
+       struct iw_statistics*   (*get_wireless_stats)(struct net_device *dev);
 };
 
 /* ---------------------- IOCTL DESCRIPTION ---------------------- */
@@ -374,18 +387,29 @@ struct iw_ioctl_description
  */
 struct iw_spy_data
 {
-#ifdef IW_WIRELESS_SPY
        /* --- Standard spy support --- */
        int                     spy_number;
        u_char                  spy_address[IW_MAX_SPY][ETH_ALEN];
        struct iw_quality       spy_stat[IW_MAX_SPY];
-#ifdef IW_WIRELESS_THRSPY
        /* --- Enhanced spy support (event) */
        struct iw_quality       spy_thr_low;    /* Low threshold */
        struct iw_quality       spy_thr_high;   /* High threshold */
        u_char                  spy_thr_under[IW_MAX_SPY];
-#endif /* IW_WIRELESS_THRSPY */
-#endif /* IW_WIRELESS_SPY */
+};
+
+/* --------------------- DEVICE WIRELESS DATA --------------------- */
+/*
+ * This is all the wireless data specific to a device instance that
+ * is managed by the core of Wireless Extensions.
+ * We only keep pointer to those structures, so that a driver is free
+ * to share them between instances.
+ * This structure should be initialised before registering the device.
+ * Access to this data follow the same rules as any other struct net_device
+ * data (i.e. valid as long as struct net_device exist, same locking rules).
+ */
+struct iw_public_data {
+       /* Driver enhanced spy support */
+       struct iw_spy_data *    spy_data;
 };
 
 /**************************** PROTOTYPES ****************************/
@@ -394,6 +418,9 @@ struct iw_spy_data
  * Those may be called only within the kernel.
  */
 
+/* Data needed by fs/compat_ioctl.c for 32->64 bit conversion */
+extern const char iw_priv_type_size[];
+
 /* First : function strictly used inside the kernel */
 
 /* Handle /proc/net/wireless, called in net/code/dev.c */
index 61d7033..8f12190 100644 (file)
@@ -45,6 +45,11 @@ struct nd_msg {
        __u8            opt[0];
 };
 
+struct rs_msg {
+       struct icmp6hdr icmph;
+       __u8            opt[0];
+};
+
 struct ra_msg {
         struct icmp6hdr                icmph;
        __u32                   reachable_time;
index e7e7da3..bf55ad5 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -60,7 +60,7 @@ tcf_hash_destroy(struct tcf_st *p)
                        *p1p = p->next;
                        write_unlock_bh(&tcf_t_lock);
 #ifdef CONFIG_NET_ESTIMATOR
-                       qdisc_kill_estimator(&p->stats);
+                       gen_kill_estimator(&p->bstats, &p->rate_est);
 #endif
                        kfree(p);
                        return;
@@ -256,9 +256,8 @@ tcf_hash_create(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int
        p->tm.install = jiffies;
        p->tm.lastuse = jiffies;
 #ifdef CONFIG_NET_ESTIMATOR
-       if (est) {
-               qdisc_new_estimator(&p->stats, p->stats_lock, est);
-       }
+       if (est)
+               gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
 #endif
        h = tcf_hash(p->index);
        write_lock_bh(&tcf_t_lock);
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
index 26c97aa..3bd04bc 100644 (file)
@@ -266,6 +266,7 @@ struct sctp_opt {
        __u8 disable_fragments;
        __u8 pd_mode;
        __u8 v4mapped;
+       __u32 adaption_ind;
 
        /* Receive to here while partial delivery is in effect. */
        struct sk_buff_head pd_lobby;
@@ -323,6 +324,8 @@ struct sctp_cookie {
 
        __u8 prsctp_capable;
 
+       __u32 adaption_ind;     
+
        /* This is a shim for my peer's INIT packet, followed by
         * a copy of the raw address list of the association.
         * The length of the raw address list is saved in the
@@ -362,6 +365,7 @@ union sctp_params {
        struct sctp_ipv4addr_param *v4;
        struct sctp_ipv6addr_param *v6;
        union sctp_addr_param *addr;
+       struct sctp_adaption_ind_param *aind;
 };
 
 /* RFC 2960.  Section 3.3.5 Heartbeat.
@@ -1395,6 +1399,8 @@ struct sctp_association {
                __u8    asconf_capable;  /* Does peer support ADDIP? */
                __u8    prsctp_capable;  /* Can peer do PR-SCTP? */
 
+               __u32   adaption_ind;    /* Adaption Code point. */
+
                /* This mask is used to disable sending the ASCONF chunk
                 * with specified parameter to peer.
                 */
index ff9c757..46a9744 100644 (file)
@@ -121,6 +121,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
        const struct sctp_association *asoc,
        __u32 indication, int gfp);
 
+struct sctp_ulpevent *sctp_ulpevent_make_adaption_indication(
+       const struct sctp_association *asoc, int gfp);
+
 struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
        struct sctp_chunk *chunk,
        int gfp);
index 04e9917..2758e8c 100644 (file)
@@ -55,7 +55,7 @@
 #include <linux/types.h>
 #include <linux/socket.h>
 
-typedef void * sctp_assoc_t;
+typedef __s32 sctp_assoc_t;
 
 /* The following symbols come from the Sockets API Extensions for
  * SCTP <draft-ietf-tsvwg-sctpsocket-07.txt>.
@@ -338,8 +338,8 @@ struct sctp_adaption_event {
 /*
  * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT
  *
- *   When a reciever is engaged in a partial delivery of a
- *   message this notification will be used to inidicate
+ *   When a receiver is engaged in a partial delivery of a
+ *   message this notification will be used to indicate
  *   various events.
  */
 struct sctp_pdapi_event {
index 8401ce1..59f0d96 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __NET_TC_GACT_H
 #define __NET_TC_GACT_H
 
-#include <net/pkt_sched.h>
+#include <net/act_api.h>
 
 struct tcf_gact
 {
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
index 2ef99a7..c496d10 100644 (file)
@@ -71,6 +71,8 @@ extern int    udp_sendmsg(struct kiocb *iocb, struct sock *sk,
 extern int     udp_rcv(struct sk_buff *skb);
 extern int     udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern int     udp_disconnect(struct sock *sk, int flags);
+extern unsigned int udp_poll(struct file *file, struct socket *sock,
+                            poll_table *wait);
 
 DECLARE_SNMP_STAT(struct udp_mib, udp_statistics);
 #define UDP_INC_STATS(field)           SNMP_INC_STATS(udp_statistics, field)
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
index c21d64d..f695422 100644 (file)
@@ -53,155 +53,7 @@ typedef struct region_info_t {
 #define REGION_BAR_MASK                0xe000
 #define REGION_BAR_SHIFT       13
 
-/* For OpenMemory */
-typedef struct open_mem_t {
-    u_int              Attributes;
-    u_int              Offset;
-} open_mem_t;
-
-/* Attributes for OpenMemory */
-#define MEMORY_TYPE            0x0001
-#define MEMORY_TYPE_CM         0x0000
-#define MEMORY_TYPE_AM         0x0001
-#define MEMORY_EXCLUSIVE       0x0002
-#define MEMORY_PREFETCH                0x0008
-#define MEMORY_CACHEABLE       0x0010
-#define MEMORY_BAR_MASK                0xe000
-#define MEMORY_BAR_SHIFT       13
-
-typedef struct eraseq_entry_t {
-    memory_handle_t    Handle;
-    u_char             State;
-    u_int              Size;
-    u_int              Offset;
-    void               *Optional;
-} eraseq_entry_t;
-
-typedef struct eraseq_hdr_t {
-    int                        QueueEntryCnt;
-    eraseq_entry_t     *QueueEntryArray;
-} eraseq_hdr_t;
-
-#define ERASE_QUEUED           0x00
-#define ERASE_IN_PROGRESS(n)   (((n) > 0) && ((n) < 0x80))
-#define ERASE_IDLE             0xff
-#define ERASE_PASSED           0xe0
-#define ERASE_FAILED           0xe1
-
-#define ERASE_MISSING          0x80
-#define ERASE_MEDIA_WRPROT     0x84
-#define ERASE_NOT_ERASABLE     0x85
-#define ERASE_BAD_OFFSET       0xc1
-#define ERASE_BAD_TECH         0xc2
-#define ERASE_BAD_SOCKET       0xc3
-#define ERASE_BAD_VCC          0xc4
-#define ERASE_BAD_VPP          0xc5
-#define ERASE_BAD_SIZE         0xc6
-
-/* For CopyMemory */
-typedef struct copy_op_t {
-    u_int              Attributes;
-    u_int              SourceOffset;
-    u_int              DestOffset;
-    u_int              Count;
-} copy_op_t;
-
-/* For ReadMemory and WriteMemory */
-typedef struct mem_op_t {
-    u_int      Attributes;
-    u_int      Offset;
-    u_int      Count;
-} mem_op_t;
-
-#define MEM_OP_BUFFER          0x01
-#define MEM_OP_BUFFER_USER     0x00
-#define MEM_OP_BUFFER_KERNEL   0x01
-#define MEM_OP_DISABLE_ERASE   0x02
-#define MEM_OP_VERIFY          0x04
-
-/* For RegisterMTD */
-typedef struct mtd_reg_t {
-    u_int      Attributes;
-    u_int      Offset;
-    u_long     MediaID;
-} mtd_reg_t;
-
-/*
- *  Definitions for MTD requests
- */
-
-typedef struct mtd_request_t {
-    u_int      SrcCardOffset;
-    u_int      DestCardOffset;
-    u_int      TransferLength;
-    u_int      Function;
-    u_long     MediaID;
-    u_int      Status;
-    u_int      Timeout;
-} mtd_request_t;
-
-/* Fields in MTD Function */
-#define MTD_REQ_ACTION         0x003
-#define MTD_REQ_ERASE          0x000
-#define MTD_REQ_READ           0x001
-#define MTD_REQ_WRITE          0x002
-#define MTD_REQ_COPY           0x003
-#define MTD_REQ_NOERASE                0x004
-#define MTD_REQ_VERIFY         0x008
-#define MTD_REQ_READY          0x010
-#define MTD_REQ_TIMEOUT                0x020
-#define MTD_REQ_LAST           0x040
-#define MTD_REQ_FIRST          0x080
-#define MTD_REQ_KERNEL         0x100
-
-/* Status codes */
-#define MTD_WAITREQ    0x00
-#define MTD_WAITTIMER  0x01
-#define MTD_WAITRDY    0x02
-#define MTD_WAITPOWER  0x03
-
-/*
- *  Definitions for MTD helper functions
- */
-
-/* For MTDModifyWindow */
-typedef struct mtd_mod_win_t {
-    u_int      Attributes;
-    u_int      AccessSpeed;
-    u_int      CardOffset;
-} mtd_mod_win_t;
-
-/* For MTDSetVpp */
-typedef struct mtd_vpp_req_t {
-    u_char     Vpp1, Vpp2;
-} mtd_vpp_req_t;
-
-/* For MTDRDYMask */
-typedef struct mtd_rdy_req_t {
-    u_int      Mask;
-} mtd_rdy_req_t;
-
-enum mtd_helper {
-    MTDRequestWindow, MTDModifyWindow, MTDReleaseWindow,
-    MTDSetVpp, MTDRDYMask
-};
-
-#ifdef IN_CARD_SERVICES
-extern int MTDHelperEntry(int func, void *a1, void *a2);
-#else
-extern int MTDHelperEntry(int func, ...);
-#endif
-
 int pcmcia_get_first_region(client_handle_t handle, region_info_t *rgn);
 int pcmcia_get_next_region(client_handle_t handle, region_info_t *rgn);
-int pcmcia_register_mtd(client_handle_t handle, mtd_reg_t *reg);
-int pcmcia_register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header, eraseq_handle_t *e);
-int pcmcia_deregister_erase_queue(eraseq_handle_t eraseq);
-int pcmcia_check_erase_queue(eraseq_handle_t eraseq);
-int pcmcia_open_memory(client_handle_t *handle, open_mem_t *open, memory_handle_t *m);
-int pcmcia_close_memory(memory_handle_t handle);
-int pcmcia_read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf);
-int pcmcia_write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf);
-int pcmcia_copy_memory(memory_handle_t handle, copy_op_t *req);
 
 #endif /* _LINUX_BULKMEM_H */
index a14f0b9..499f748 100644 (file)
@@ -607,6 +607,14 @@ int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple);
 int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse);
 
 int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info);
-int pcmcia_replace_cis(client_handle_t handle, cisdump_t *cis);
+int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis);
+
+/* don't use outside of PCMCIA core yet */
+int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int func, tuple_t *tuple);
+int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple);
+int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
+int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse);
+
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info);
 
 #endif /* LINUX_CISTPL_H */
index 871d8f1..48eddee 100644 (file)
@@ -348,7 +348,6 @@ typedef struct mtd_bind_t {
 #define CS_EVENT_RESET_PHYSICAL                0x000200
 #define CS_EVENT_CARD_RESET            0x000400
 #define CS_EVENT_REGISTRATION_COMPLETE 0x000800
-#define CS_EVENT_RESET_COMPLETE                0x001000
 #define CS_EVENT_PM_SUSPEND            0x002000
 #define CS_EVENT_PM_RESUME             0x004000
 #define CS_EVENT_INSERTION_REQUEST     0x008000
@@ -425,16 +424,12 @@ int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg
 int pcmcia_deregister_client(client_handle_t handle);
 int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config);
 int pcmcia_get_card_services_info(servinfo_t *info);
-int pcmcia_get_first_client(client_handle_t *handle, client_req_t *req);
-int pcmcia_get_next_client(client_handle_t *handle, client_req_t *req);
-int pcmcia_get_window(window_handle_t *handle, int idx, win_req_t *req);
 int pcmcia_get_first_window(window_handle_t *win, win_req_t *req);
 int pcmcia_get_next_window(window_handle_t *win, win_req_t *req);
 int pcmcia_get_status(client_handle_t handle, cs_status_t *status);
 int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
 int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
 int pcmcia_modify_configuration(client_handle_t handle, modconf_t *mod);
-int pcmcia_modify_window(window_handle_t win, modwin_t *req);
 int pcmcia_register_client(client_handle_t *handle, client_reg_t *req);
 int pcmcia_release_configuration(client_handle_t handle);
 int pcmcia_release_io(client_handle_t handle, io_req_t *req);
@@ -449,12 +444,14 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt);
 int pcmcia_resume_card(struct pcmcia_socket *skt);
 int pcmcia_eject_card(struct pcmcia_socket *skt);
 int pcmcia_insert_card(struct pcmcia_socket *skt);
-int pcmcia_set_event_mask(client_handle_t handle, eventmask_t *mask);
 int pcmcia_report_error(client_handle_t handle, error_info_t *err);
-struct pci_bus *pcmcia_lookup_bus(client_handle_t handle);
 
-/* rsrc_mgr.c */
-int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj);
+#ifdef CONFIG_PCMCIA_OBSOLETE
+int pcmcia_get_first_client(client_handle_t *handle, client_req_t *req);
+int pcmcia_get_next_client(client_handle_t *handle, client_req_t *req);
+int pcmcia_modify_window(window_handle_t win, modwin_t *req);
+int pcmcia_set_event_mask(client_handle_t handle, eventmask_t *mask);
+#endif
 
 #endif /* __KERNEL__ */
 
index 93e0427..7ce3aa6 100644 (file)
@@ -32,13 +32,13 @@ typedef enum {
 typedef struct _snd_hdsp_peak_rms hdsp_peak_rms_t;
 
 struct _snd_hdsp_peak_rms {
-       unsigned int input_peaks[26];
-       unsigned int playback_peaks[26];
-       unsigned int output_peaks[28];
-       unsigned long long input_rms[26];
-       unsigned long long playback_rms[26];
+       u32 input_peaks[26];
+       u32 playback_peaks[26];
+       u32 output_peaks[28];
+       u64 input_rms[26];
+       u64 playback_rms[26];
        /* These are only used for H96xx cards */
-       unsigned long long output_rms[26];
+       u64 output_rms[26];
 };
 
 #define SNDRV_HDSP_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, hdsp_peak_rms_t)
@@ -76,7 +76,7 @@ struct _snd_hdsp_config_info {
 typedef struct _snd_hdsp_firmware hdsp_firmware_t;
 
 struct _snd_hdsp_firmware {
-       unsigned long __user *firmware_data;    /* 24413 long words */
+       void __user *firmware_data;     /* 24413 x 4 bytes */
 };
 
 #define SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE _IOW('H', 0x42, hdsp_firmware_t)
index 48fcf7c..19f657d 100644 (file)
@@ -274,6 +274,9 @@ struct snd_opl3 {
        snd_timer_t *timer2;
        spinlock_t timer_lock;
 
+       void *private_data;
+       void (*private_free)(opl3_t *);
+
        spinlock_t reg_lock;
        snd_card_t *card;               /* The card that this belongs to */
        int used;                       /* usage flag - exclusive */
@@ -314,6 +317,8 @@ struct snd_opl3 {
 
 /* opl3.c */
 void snd_opl3_interrupt(snd_hwdep_t * hw);
+int snd_opl3_new(snd_card_t *card, unsigned short hardware, opl3_t **ropl3);
+int snd_opl3_init(opl3_t *opl3);
 int snd_opl3_create(snd_card_t * card,
                    unsigned long l_port, unsigned long r_port,
                    unsigned short hardware,
index c780e10..888e322 100644 (file)
@@ -364,6 +364,7 @@ struct _snd_pcm_runtime {
 typedef struct _snd_pcm_group {                /* keep linked substreams */
        spinlock_t lock;
        struct list_head substreams;
+       int count;
 } snd_pcm_group_t;
 
 struct _snd_pcm_substream {
@@ -405,6 +406,8 @@ struct _snd_pcm_substream {
        snd_info_entry_t *proc_sw_params_entry;
        snd_info_entry_t *proc_status_entry;
        snd_info_entry_t *proc_prealloc_entry;
+       /* misc flags */
+       unsigned int no_mmap_ctrl: 1;
 };
 
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
@@ -486,6 +489,7 @@ int snd_pcm_status(snd_pcm_substream_t * substream, snd_pcm_status_t *status);
 int snd_pcm_prepare(snd_pcm_substream_t *substream);
 int snd_pcm_start(snd_pcm_substream_t *substream);
 int snd_pcm_stop(snd_pcm_substream_t *substream, int status);
+int snd_pcm_drain_done(snd_pcm_substream_t *substream);
 #ifdef CONFIG_PM
 int snd_pcm_suspend(snd_pcm_substream_t *substream);
 int snd_pcm_suspend_all(snd_pcm_t *pcm);
index a64fb3f..4beca19 100644 (file)
@@ -180,4 +180,12 @@ int snd_seq_event_port_attach(int client, snd_seq_port_callback_t *pcbp,
                              int cap, int type, int midi_channels, int midi_voices, char *portname);
 int snd_seq_event_port_detach(int client, int port);
 
+#ifdef CONFIG_KMOD
+void snd_seq_autoload_lock(void);
+void snd_seq_autoload_unlock(void);
+#else
+#define snd_seq_autoload_lock()
+#define snd_seq_autoload_unlock()
+#endif
+
 #endif /* __SOUND_SEQ_KERNEL_H */
index c5f9b0f..6996149 100644 (file)
@@ -13,7 +13,7 @@
 #define _KYRO_H
 
 struct kyrofb_info {
-       void *regbase;
+       void __iomem *regbase;
 
        u32 HTot;       /* Hor Total Time    */
        u32 HFP;        /* Hor Front Porch   */
index 8ca47b7..09a7f4a 100644 (file)
@@ -68,6 +68,8 @@
 
 #define I2C_CNTL_0             0x003C  /* Dword offset 0_0F */
 
+#define DSTN_CONTROL_LG                0x003C  /* Dword offset 0_0F (LG) */
+
 /* Overscan */
 #define OVR_CLR                        0x0040  /* Dword offset 0_10 */
 #define OVR2_CLR               0x0040  /* Dword offset 0_10 */
 #define CUR_HORZ_VERT_OFF      0x0070  /* Dword offset 0_1C */
 #define CUR2_HORZ_VERT_OFF     0x0070  /* Dword offset 0_1C */
 
-#define CONFIG_PANEL_LG                0x0074  /* Dword offset 0_1D */
+#define CONFIG_PANEL_LG                0x0074  /* Dword offset 0_1D (LG) */
 
 /* General I/O Control */
 #define GP_IO                  0x0078  /* Dword offset 0_1E */
 #define SCRATCH_REG3           0x008C  /* Dword offset 0_23 */
 
 /* Clock Control */
-#define CLOCK_CNTL             0x0090  /* Dword offset 0_24 */
+#define CLOCK_CNTL                     0x0090  /* Dword offset 0_24 */
+/* CLOCK_CNTL register constants CT LAYOUT */
+#define CLOCK_SEL                      0x0f
+#define CLOCK_SEL_INTERNAL             0x03
+#define CLOCK_SEL_EXTERNAL             0x0c
+#define CLOCK_DIV                      0x30
+#define CLOCK_DIV1                     0x00
+#define CLOCK_DIV2                     0x10
+#define CLOCK_DIV4                     0x20
+#define CLOCK_STROBE                   0x40
+/*  ?                                  0x80 */
+/* CLOCK_CNTL register constants GX LAYOUT */
+#define CLOCK_BIT                      0x04    /* For ICS2595 */
+#define CLOCK_PULSE                    0x08    /* For ICS2595 */
+/*#define CLOCK_STROBE                 0x40 dito as CT */
+#define CLOCK_DATA                     0x80
+
+/* For internal PLL(CT) start */
+#define CLOCK_CNTL_ADDR                        CLOCK_CNTL + 1
+#define PLL_WR_EN                      0x02
+#define PLL_ADDR                       0xfc
+#define CLOCK_CNTL_DATA                        CLOCK_CNTL + 2
+#define PLL_DATA                       0xff
+/* For internal PLL(CT) end */
+
 #define CLOCK_SEL_CNTL         0x0090  /* Dword offset 0_24 */
 
 /* Configuration */
 #define LCD_INDEX              0x00A4  /* Dword offset 0_29 */
 #define LCD_DATA               0x00A8  /* Dword offset 0_2A */
 
+#define HFB_PITCH_ADDR_LG      0x00A8  /* Dword offset 0_2A (LG) */
+
 /* Memory Control */
 #define EXT_MEM_CNTL           0x00AC  /* Dword offset 0_2B */
 #define MEM_CNTL               0x00B0  /* Dword offset 0_2C */
 
 #define I2C_CNTL_1             0x00BC  /* Dword offset 0_2F */
 
+#define LT_GIO_LG              0x00BC  /* Dword offset 0_2F (LG) */
+
 /* DAC Control */
 #define DAC_REGS               0x00C0  /* Dword offset 0_30 */
 #define DAC_W_INDEX            0x00C0  /* Dword offset 0_30 */
 
 #define EXT_DAC_REGS           0x00C8  /* Dword offset 0_32 */
 
+#define HORZ_STRETCHING_LG     0x00C8  /* Dword offset 0_32 (LG) */
+#define VERT_STRETCHING_LG     0x00CC  /* Dword offset 0_33 (LG) */
+
 /* Test and Debug */
 #define GEN_TEST_CNTL          0x00D0  /* Dword offset 0_34 */
 
 /* Custom Macros */
 #define CUSTOM_MACRO_CNTL      0x00D4  /* Dword offset 0_35 */
 
-#define LCD_GEN_CNTL_LG                0x00D4  /* Dword offset 0_35 */
-
+#define LCD_GEN_CNTL_LG                0x00D4  /* Dword offset 0_35 (LG) */
 #define POWER_MANAGEMENT_LG    0x00D8  /* Dword offset 0_36 (LG) */
 
 /* Configuration */
 #define CRTC_CSYNC_EN          0x00000010
 #define CRTC_PIX_BY_2_EN       0x00000020      /* unused on RAGE */
 #define CRTC_DISPLAY_DIS       0x00000040
-#define CRTC_VGA_XOVERSCAN     0x00000040
+#define CRTC_VGA_XOVERSCAN     0x00000080
 
 #define CRTC_PIX_WIDTH_MASK    0x00000700
 #define CRTC_PIX_WIDTH_4BPP    0x00000100
 #define CRTC_PIX_ORDER_MSN_LSN 0x00000000
 #define CRTC_PIX_ORDER_LSN_MSN 0x00000800
 
+#define CRTC_VSYNC_INT_EN      0x00001000ul    /* XC/XL */
+#define CRTC_VSYNC_INT         0x00002000ul    /* XC/XL */
+#define CRTC_FIFO_OVERFILL     0x0000c000ul    /* VT/GT */
+#define CRTC2_VSYNC_INT_EN     0x00004000ul    /* XC/XL */
+#define CRTC2_VSYNC_INT                0x00008000ul    /* XC/XL */
+
 #define CRTC_FIFO_LWM          0x000f0000
+#define CRTC_HVSYNC_IO_DRIVE   0x00010000      /* XC/XL */
+#define CRTC2_PIX_WIDTH                0x000e0000      /* LTPro */
 
-#define VGA_128KAP_PAGING      0x00100000
-#define VFC_SYNC_TRISTATE      0x00200000
+#define CRTC_VGA_128KAP_PAGING 0x00100000
+#define CRTC_VFC_SYNC_TRISTATE 0x00200000      /* VTB/GTB/LT */
+#define CRTC2_EN               0x00200000      /* LTPro */
 #define CRTC_LOCK_REGS         0x00400000
 #define CRTC_SYNC_TRISTATE     0x00800000
 
 #define CRTC_EXT_DISP_EN       0x01000000
-#define CRTC_ENABLE            0x02000000
-#define CRTC_DISP_REQ_ENB      0x04000000
-#define VGA_ATI_LINEAR         0x08000000
+#define CRTC_EN                        0x02000000
+#define CRTC_DISP_REQ_EN       0x04000000
+#define CRTC_VGA_LINEAR                0x08000000
 #define CRTC_VSYNC_FALL_EDGE   0x10000000
-#define VGA_TEXT_132           0x20000000
-#define VGA_XCRT_CNT_EN                0x40000000
-#define VGA_CUR_B_TEST         0x80000000
+#define CRTC_VGA_TEXT_132      0x20000000
+#define CRTC_CNT_EN            0x40000000
+#define CRTC_CUR_B_TEST                0x80000000
 
 #define CRTC_CRNT_VLINE                0x07f00000
-#define CRTC_VBLANK            0x00000001
 
+#define CRTC_PRESERVED_MASK    0x0001f000
+
+#define CRTC_VBLANK            0x00000001
+#define CRTC_VBLANK_INT_EN     0x00000002
+#define CRTC_VBLANK_INT                0x00000004
+#define CRTC_VBLANK_INT_AK     CRTC_VBLANK_INT
+#define CRTC_VLINE_INT_EN      0x00000008
+#define CRTC_VLINE_INT         0x00000010
+#define CRTC_VLINE_INT_AK      CRTC_VLINE_INT
+#define CRTC_VLINE_SYNC                0x00000020
+#define CRTC_FRAME             0x00000040
+#define SNAPSHOT_INT_EN                0x00000080
+#define SNAPSHOT_INT           0x00000100
+#define SNAPSHOT_INT_AK                SNAPSHOT_INT
+#define I2C_INT_EN             0x00000200
+#define I2C_INT                        0x00000400
+#define I2C_INT_AK             I2C_INT
+#define CRTC2_VBLANK           0x00000800
+#define CRTC2_VBLANK_INT_EN    0x00001000
+#define CRTC2_VBLANK_INT       0x00002000
+#define CRTC2_VBLANK_INT_AK    CRTC2_VBLANK_INT
+#define CRTC2_VLINE_INT_EN     0x00004000
+#define CRTC2_VLINE_INT                0x00008000
+#define CRTC2_VLINE_INT_AK     CRTC2_VLINE_INT
+#define CAPBUF0_INT_EN         0x00010000
+#define CAPBUF0_INT            0x00020000
+#define CAPBUF0_INT_AK         CAPBUF0_INT
+#define CAPBUF1_INT_EN         0x00040000
+#define CAPBUF1_INT            0x00080000
+#define CAPBUF1_INT_AK         CAPBUF1_INT
+#define OVERLAY_EOF_INT_EN     0x00100000
+#define OVERLAY_EOF_INT                0x00200000
+#define OVERLAY_EOF_INT_AK     OVERLAY_EOF_INT
+#define ONESHOT_CAP_INT_EN     0x00400000
+#define ONESHOT_CAP_INT                0x00800000
+#define ONESHOT_CAP_INT_AK     ONESHOT_CAP_INT
+#define BUSMASTER_EOL_INT_EN   0x01000000
+#define BUSMASTER_EOL_INT      0x02000000
+#define BUSMASTER_EOL_INT_AK   BUSMASTER_EOL_INT
+#define GP_INT_EN              0x04000000
+#define GP_INT                 0x08000000
+#define GP_INT_AK              GP_INT
+#define CRTC2_VLINE_SYNC       0x10000000
+#define SNAPSHOT2_INT_EN       0x20000000
+#define SNAPSHOT2_INT          0x40000000
+#define SNAPSHOT2_INT_AK       SNAPSHOT2_INT
+#define VBLANK_BIT2_INT                0x80000000
+#define VBLANK_BIT2_INT_AK     VBLANK_BIT2_INT
+
+#define CRTC_INT_EN_MASK       (CRTC_VBLANK_INT_EN |   \
+                                CRTC_VLINE_INT_EN |    \
+                                SNAPSHOT_INT_EN |      \
+                                I2C_INT_EN |           \
+                                CRTC2_VBLANK_INT_EN |  \
+                                CRTC2_VLINE_INT_EN |   \
+                                CAPBUF0_INT_EN |       \
+                                CAPBUF1_INT_EN |       \
+                                OVERLAY_EOF_INT_EN |   \
+                                ONESHOT_CAP_INT_EN |   \
+                                BUSMASTER_EOL_INT_EN | \
+                                GP_INT_EN |            \
+                                SNAPSHOT2_INT_EN)
 
 /* DAC control values */
 
 #define DAC_BLANK_ADJ_1                0x00000800
 #define DAC_BLANK_ADJ_2                0x00001000
 
+/* DAC control values (my source XL/XC Register reference) */
+#define DAC_OUTPUT_MASK         0x00000001  /* 0 - PAL, 1 - NTSC */
+#define DAC_MISTERY_BIT         0x00000002  /* PS2 ? RS343 ?, EXTRA_BRIGHT for GT */
+#define DAC_BLANKING            0x00000004
+#define DAC_CMP_DISABLE         0x00000008
+#define DAC1_CLK_SEL            0x00000010
+#define PALETTE_ACCESS_CNTL     0x00000020
+#define PALETTE2_SNOOP_EN       0x00000040
+#define DAC_CMP_OUTPUT          0x00000080 /* read only */
+/* #define DAC_8BIT_EN is ok */
+#define CRT_SENSE               0x00000800 /* read only */
+#define CRT_DETECTION_ON        0x00001000
+#define DAC_VGA_ADR_EN          0x00002000
+#define DAC_FEA_CON_EN          0x00004000
+#define DAC_PDWN                0x00008000
+#define DAC_TYPE_MASK           0x00070000 /* read only */
+
+
 
 /* Mix control values */
 
 /* Mach64 engine bit constants - these are typically ORed together */
 
 /* BUS_CNTL register constants */
+#define BUS_APER_REG_DIS       0x00000010
 #define BUS_FIFO_ERR_ACK       0x00200000
 #define BUS_HOST_ERR_ACK       0x00800000
 
 /* DSP_ON_OFF register constants */
 #define DSP_OFF                        0x000007ff
 #define DSP_ON                 0x07ff0000
+#define VGA_DSP_OFF            DSP_OFF
+#define VGA_DSP_ON             DSP_ON
+#define VGA_DSP_XCLKS_PER_QW   DSP_XCLKS_PER_QW
 
-/* CLOCK_CNTL register constants */
-#define CLOCK_SEL              0x0f
-#define CLOCK_DIV              0x30
-#define CLOCK_DIV1             0x00
-#define CLOCK_DIV2             0x10
-#define CLOCK_DIV4             0x20
-#define CLOCK_STROBE           0x40
-#define PLL_WR_EN              0x02
-
-/* PLL register indices */
+/* PLL register indices and fields */
 #define MPLL_CNTL              0x00
+#define PLL_PC_GAIN            0x07
+#define PLL_VC_GAIN            0x18
+#define PLL_DUTY_CYC           0xE0
 #define VPLL_CNTL              0x01
 #define PLL_REF_DIV            0x02
 #define PLL_GEN_CNTL           0x03
+#define PLL_OVERRIDE           0x01    /* PLL_SLEEP */
+#define PLL_MCLK_RST           0x02    /* PLL_MRESET */
+#define OSC_EN                 0x04
+#define EXT_CLK_EN             0x08
+#define FORCE_DCLK_TRI_STATE   0x08    /* VT4 -> */
+#define MCLK_SRC_SEL           0x70
+#define EXT_CLK_CNTL           0x80
+#define DLL_PWDN               0x80    /* VT4 -> */
 #define MCLK_FB_DIV            0x04
 #define PLL_VCLK_CNTL          0x05
+#define PLL_VCLK_SRC_SEL       0x03
+#define PLL_VCLK_RST           0x04
+#define PLL_VCLK_INVERT                0x08
 #define VCLK_POST_DIV          0x06
+#define VCLK0_POST             0x03
+#define VCLK1_POST             0x0C
+#define VCLK2_POST             0x30
+#define VCLK3_POST             0xC0
 #define VCLK0_FB_DIV           0x07
 #define VCLK1_FB_DIV           0x08
 #define VCLK2_FB_DIV           0x09
 #define VCLK3_FB_DIV           0x0A
 #define PLL_EXT_CNTL           0x0B
+#define PLL_XCLK_MCLK_RATIO    0x03
+#define PLL_XCLK_SRC_SEL       0x07
+#define PLL_MFB_TIMES_4_2B     0x08
+#define PLL_VCLK0_XDIV         0x10
+#define PLL_VCLK1_XDIV         0x20
+#define PLL_VCLK2_XDIV         0x40
+#define PLL_VCLK3_XDIV         0x80
 #define DLL_CNTL               0x0C
 #define DLL1_CNTL              0x0C
 #define VFC_CNTL               0x0D
 #define SPLL_CNTL2             0x17
 #define APLL_STRAPS            0x18
 #define EXT_VPLL_CNTL          0x19
+#define EXT_VPLL_EN            0x04
+#define EXT_VPLL_VGA_EN                0x08
+#define EXT_VPLL_INSYNC                0x10
 #define EXT_VPLL_REF_DIV       0x1A
 #define EXT_VPLL_FB_DIV                0x1B
 #define EXT_VPLL_MSB           0x1C
 #define PLL_YCLK_CNTL          0x29
 #define PM_DYN_CLK_CNTL                0x2A
 
-/* Fields in PLL registers */
-#define PLL_PC_GAIN            0x07
-#define PLL_VC_GAIN            0x18
-#define PLL_DUTY_CYC           0xE0
-#define PLL_OVERRIDE           0x01
-#define PLL_MCLK_RST           0x02
-#define OSC_EN                 0x04
-#define EXT_CLK_EN             0x08
-#define MCLK_SRC_SEL           0x70
-#define EXT_CLK_CNTL           0x80
-#define VCLK_SRC_SEL           0x03
-#define PLL_VCLK_RST           0x04
-#define VCLK_INVERT            0x08
-#define VCLK0_POST             0x03
-#define VCLK1_POST             0x0C
-#define VCLK2_POST             0x30
-#define VCLK3_POST             0xC0
-
 /* CONFIG_CNTL register constants */
 #define APERTURE_4M_ENABLE     1
 #define APERTURE_8M_ENABLE     2
 #define MEM_BNDRY_1M           0x00030000
 #define MEM_BNDRY_EN           0x00040000
 
+#define ONE_MB                 0x100000
 /* ATI PCI constants */
 #define PCI_ATI_VENDOR_ID      0x1002
 
 #define LI_CHIP_ID     0x4c49  /* RAGE LT PRO */
 #define LP_CHIP_ID     0x4c50  /* RAGE LT PRO */
 #define LT_CHIP_ID     0x4c54  /* RAGE LT */
-#define XL_CHIP_ID     0x4752  /* RAGE (XL) */
+
+/* mach64CT family / (Rage XL) class */
+#define GR_CHIP_ID     0x4752  /* RAGE XL, BGA, PCI33 */
+#define GS_CHIP_ID     0x4753  /* RAGE XL, PQFP, PCI33 */
+#define GM_CHIP_ID     0x474d  /* RAGE XL, BGA, AGP 1x,2x */
+#define GN_CHIP_ID     0x474e  /* RAGE XL, PQFP,AGP 1x,2x */
+#define GO_CHIP_ID     0x474f  /* RAGE XL, BGA, PCI66 */
+#define GL_CHIP_ID     0x474c  /* RAGE XL, PQFP, PCI66 */
+
+#define IS_XL(id) ((id)==GR_CHIP_ID || (id)==GS_CHIP_ID || \
+                  (id)==GM_CHIP_ID || (id)==GN_CHIP_ID || \
+                  (id)==GO_CHIP_ID || (id)==GL_CHIP_ID)
+
 #define GT_CHIP_ID     0x4754  /* RAGE (GT) */
 #define GU_CHIP_ID     0x4755  /* RAGE II/II+ (GTB) */
 #define GV_CHIP_ID     0x4756  /* RAGE IIC, PCI */
 #define GI_CHIP_ID     0x4749  /* RAGE PRO, BGA, PCI33 only */
 #define GP_CHIP_ID     0x4750  /* RAGE PRO, PQFP, PCI33, full 3D */
 #define GQ_CHIP_ID     0x4751  /* RAGE PRO, PQFP, PCI33, limited 3D */
-#define LM_CHIP_ID     0x4c4d  /* RAGE Mobility PCI */
-#define LN_CHIP_ID     0x4c4e  /* RAGE Mobility AGP */
 
+#define LM_CHIP_ID     0x4c4d  /* RAGE Mobility AGP, full function */
+#define LN_CHIP_ID     0x4c4e  /* RAGE Mobility AGP */
+#define LR_CHIP_ID     0x4c52  /* RAGE Mobility PCI, full function */
+#define LS_CHIP_ID     0x4c53  /* RAGE Mobility PCI */
 
+#define IS_MOBILITY(id) ((id)==LM_CHIP_ID || (id)==LN_CHIP_ID || \
+                       (id)==LR_CHIP_ID || (id)==LS_CHIP_ID)
 /* Mach64 major ASIC revisions */
 #define MACH64_ASIC_NEC_VT_A3          0x08
 #define MACH64_ASIC_NEC_VT_A4          0x48
 #define MACH64_UNKNOWN         0
 #define MACH64_GX              1
 #define MACH64_CX              2
-#define MACH64_CT              3
+#define MACH64_CT              3Restore
 #define MACH64_ET              4
 #define MACH64_VT              5
 #define MACH64_GT              6
 #define DP_CHAIN_32BPP         0x8080
 
 /* DP_PIX_WIDTH register constants */
-#define DST_1BPP               0
-#define DST_4BPP               1
-#define DST_8BPP               2
-#define DST_15BPP              3
-#define DST_16BPP              4
-#define DST_32BPP              6
-#define SRC_1BPP               0
+#define DST_1BPP               0x0
+#define DST_4BPP               0x1
+#define DST_8BPP               0x2
+#define DST_15BPP              0x3
+#define DST_16BPP              0x4
+#define DST_24BPP              0x5
+#define DST_32BPP              0x6
+#define DST_MASK               0xF
+#define SRC_1BPP               0x000
 #define SRC_4BPP               0x100
 #define SRC_8BPP               0x200
 #define SRC_15BPP              0x300
 #define SRC_16BPP              0x400
+#define SRC_24BPP              0x500
 #define SRC_32BPP              0x600
-#define HOST_1BPP              0
+#define SRC_MASK               0xF00
+#define DP_HOST_TRIPLE_EN      0x2000
+#define HOST_1BPP              0x00000
 #define HOST_4BPP              0x10000
 #define HOST_8BPP              0x20000
 #define HOST_15BPP             0x30000
 #define HOST_16BPP             0x40000
+#define HOST_24BPP             0x50000
 #define HOST_32BPP             0x60000
+#define HOST_MASK              0xF0000
 #define BYTE_ORDER_MSB_TO_LSB  0
 #define BYTE_ORDER_LSB_TO_MSB  0x1000000
+#define BYTE_ORDER_MASK                0x1000000
 
 /* DP_MIX register constants */
 #define BKGD_MIX_NOT_D                 0
 #define CONTEXT_CMD_DISABLE            0x80000000
 
 /* GUI_STAT register constants */
-#define ENGINE_IDLE            0
-#define ENGINE_BUSY            1
-#define SCISSOR_LEFT_FLAG      0x10
-#define SCISSOR_RIGHT_FLAG     0x20
-#define SCISSOR_TOP_FLAG       0x40
-#define SCISSOR_BOTTOM_FLAG    0x80
+#define ENGINE_IDLE                    0
+#define ENGINE_BUSY                    1
+#define SCISSOR_LEFT_FLAG              0x10
+#define SCISSOR_RIGHT_FLAG             0x20
+#define SCISSOR_TOP_FLAG               0x40
+#define SCISSOR_BOTTOM_FLAG            0x80
 
 /* ATI VGA Extended Regsiters */
 #define sioATIEXT              0x1ce
 #define ATI36                  0xb6
 
 /* VGA Graphics Controller Registers */
+#define R_GENMO                        0x3cc
 #define VGAGRA                 0x3ce
 #define GRA06                  0x06
 
 
 /* LCD register indices */
 #define CONFIG_PANEL           0x00
-#define LCD_GEN_CTRL           0x01
+#define LCD_GEN_CNTL           0x01
 #define DSTN_CONTROL           0x02
 #define HFB_PITCH_ADDR         0x03
 #define HORZ_STRETCHING                0x04
 #define APC_LUT_MN             0x39
 #define APC_LUT_OP             0x3A
 
+/* Values in LCD_GEN_CTRL */
+#define CRT_ON                          0x00000001ul
+#define LCD_ON                          0x00000002ul
+#define HORZ_DIVBY2_EN                  0x00000004ul
+#define DONT_DS_ICON                    0x00000008ul
+#define LOCK_8DOT                       0x00000010ul
+#define ICON_ENABLE                     0x00000020ul
+#define DONT_SHADOW_VPAR                0x00000040ul
+#define V2CLK_PM_EN                     0x00000080ul
+#define RST_FM                          0x00000100ul
+#define DISABLE_PCLK_RESET              0x00000200ul   /* XC/XL */
+#define DIS_HOR_CRT_DIVBY2              0x00000400ul
+#define SCLK_SEL                        0x00000800ul
+#define SCLK_DELAY                      0x0000f000ul
+#define TVCLK_PM_EN                     0x00010000ul
+#define VCLK_DAC_PM_EN                  0x00020000ul
+#define VCLK_LCD_OFF                    0x00040000ul
+#define SELECT_WAIT_4MS                 0x00080000ul
+#define XTALIN_PM_EN                    0x00080000ul   /* XC/XL */
+#define V2CLK_DAC_PM_EN                 0x00100000ul
+#define LVDS_EN                         0x00200000ul
+#define LVDS_PLL_EN                     0x00400000ul
+#define LVDS_PLL_RESET                  0x00800000ul
+#define LVDS_RESERVED_BITS              0x07000000ul
+#define CRTC_RW_SELECT                  0x08000000ul   /* LTPro */
+#define USE_SHADOWED_VEND               0x10000000ul
+#define USE_SHADOWED_ROWCUR             0x20000000ul
+#define SHADOW_EN                       0x40000000ul
+#define SHADOW_RW_EN                   0x80000000ul
+
+#define LCD_SET_PRIMARY_MASK            0x07FFFBFBul
+
+/* Values in HORZ_STRETCHING */
+#define HORZ_STRETCH_BLEND             0x00000ffful
+#define HORZ_STRETCH_RATIO             0x0000fffful
+#define HORZ_STRETCH_LOOP              0x00070000ul
+#define HORZ_STRETCH_LOOP09            0x00000000ul
+#define HORZ_STRETCH_LOOP11            0x00010000ul
+#define HORZ_STRETCH_LOOP12            0x00020000ul
+#define HORZ_STRETCH_LOOP14            0x00030000ul
+#define HORZ_STRETCH_LOOP15            0x00040000ul
+/*     ?                               0x00050000ul */
+/*     ?                               0x00060000ul */
+/*     ?                               0x00070000ul */
+/*     ?                               0x00080000ul */
+#define HORZ_PANEL_SIZE                        0x0ff00000ul    /* XC/XL */
+/*     ?                               0x10000000ul */
+#define AUTO_HORZ_RATIO                        0x20000000ul    /* XC/XL */
+#define HORZ_STRETCH_MODE              0x40000000ul
+#define HORZ_STRETCH_EN                        0x80000000ul
+
+/* Values in VERT_STRETCHING */
+#define VERT_STRETCH_RATIO0            0x000003fful
+#define VERT_STRETCH_RATIO1            0x000ffc00ul
+#define VERT_STRETCH_RATIO2            0x3ff00000ul
+#define VERT_STRETCH_USE0              0x40000000ul
+#define VERT_STRETCH_EN                        0x80000000ul
+
+/* Values in EXT_VERT_STRETCH */
+#define VERT_STRETCH_RATIO3            0x000003fful
+#define FORCE_DAC_DATA                 0x000000fful
+#define FORCE_DAC_DATA_SEL             0x00000300ul
+#define VERT_STRETCH_MODE              0x00000400ul
+#define VERT_PANEL_SIZE                        0x003ff800ul
+#define AUTO_VERT_RATIO                        0x00400000ul
+#define USE_AUTO_FP_POS                        0x00800000ul
+#define USE_AUTO_LCD_VSYNC             0x01000000ul
+/*     ?                               0xfe000000ul */
 
 /* Values in LCD_MISC_CNTL */
-#define BIAS_MOD_LEVEL_MASK    0x0000ff00
-#define BIAS_MOD_LEVEL_SHIFT   8
-#define BLMOD_EN               0x00010000
-#define BIASMOD_EN             0x00020000
+#define BIAS_MOD_LEVEL_MASK            0x0000ff00
+#define BIAS_MOD_LEVEL_SHIFT           8
+#define BLMOD_EN                       0x00010000
+#define BIASMOD_EN                     0x00020000
 
-#endif /* REGMACH64_H */
+#endif                         /* REGMACH64_H */
index 96eb4a7..a896e44 100644 (file)
@@ -173,7 +173,7 @@ struct banshee_reg {
 struct tdfx_par {
   u32 max_pixclock;
 
-  void *regbase_virt;
+  void __iomem *regbase_virt;
   unsigned long iobase;
   u32 baseline;
 
index 23a1808..be2b3e9 100644 (file)
@@ -176,9 +176,9 @@ struct tga_par {
        struct pci_dev *pdev;
 
        /* Device dependent information.  */
-       void *tga_mem_base;
-       void *tga_fb_base;
-       void *tga_regs_base;
+       void __iomem *tga_mem_base;
+       void __iomem *tga_fb_base;
+       void __iomem *tga_regs_base;
        u8 tga_type;                            /* TGA_TYPE_XXX */
        u8 tga_chip_rev;                        /* dc21030 revision */
 
index 7f87ff7..51bf20e 100644 (file)
@@ -142,7 +142,7 @@ dev_t __init name_to_dev_t(char *name)
        int part;
 
 #ifdef CONFIG_SYSFS
-       sys_mkdir("/sys", 0700);
+       int mkdir_err = sys_mkdir("/sys", 0700);
        if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
                goto out;
 #endif
@@ -197,7 +197,8 @@ done:
 #ifdef CONFIG_SYSFS
        sys_umount("/sys", 0);
 out:
-       sys_rmdir("/sys");
+       if (!mkdir_err)
+               sys_rmdir("/sys");
 #endif
        return res;
 fail:
index e1be9c2..cc52647 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/kernel.h>
 #include <linux/dirent.h>
 #include <linux/string.h>
-#include <linux/syscalls.h>
 
 #include "do_mounts.h"
 
index 5fba353..ad3e5d5 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/personality.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
 #include <linux/sysctl.h>
 #include <linux/types.h>
 
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);
index ca4e28b..d3d1321 100644 (file)
@@ -84,10 +84,13 @@ int register_kprobe(struct kprobe *p)
                ret = -EEXIST;
                goto out;
        }
+
+       if ((ret = arch_prepare_kprobe(p)) != 0) {
+               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,
@@ -101,6 +104,7 @@ void unregister_kprobe(struct kprobe *p)
 {
        unsigned long flags;
        spin_lock_irqsave(&kprobe_lock, flags);
+       arch_remove_kprobe(p);
        *p->addr = p->opcode;
        hlist_del(&p->hlist);
        flush_icache_range((unsigned long) p->addr,
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);
index 67f9552..ed49ffd 100644 (file)
@@ -20,6 +20,7 @@ config PM
 
 config PM_DEBUG
        bool "Power Management Debug Support"
+       depends on PM
        ---help---
        This option enables verbose debugging support in the Power Management
        code. This is helpful when debugging and reporting various PM bugs, 
@@ -29,18 +30,18 @@ config SOFTWARE_SUSPEND
        bool "Software Suspend (EXPERIMENTAL)"
        depends on EXPERIMENTAL && PM && SWAP
        ---help---
-         Enable the possibilty of suspendig machine. It doesn't need APM.
+         Enable the possibility of suspending the machine.
+         It doesn't need APM.
          You may suspend your machine by 'swsusp' or 'shutdown -z <time>' 
          (patch for sysvinit needed). 
 
-         It creates an image which is saved in your active swaps. By the next
-         booting the, pass 'resume=/dev/swappartition' and kernel will 
-         detect the saved image, restore the memory from
-         it and then it continues to run as before you've suspended.
-         If you don't want the previous state to continue use the 'noresume'
-         kernel option. However note that your partitions will be fsck'd and
-         you must re-mkswap your swap partitions. It does not work with swap
-         files.
+         It creates an image which is saved in your active swap. Upon next
+         boot, pass the 'resume=/dev/swappartition' argument to the kernel to
+         have it detect the saved image, restore memory state from it, and
+         continue to run as before. If you do not want the previous state to
+         be reloaded, then use the 'noresume' kernel argument. However, note
+         that your partitions will be fsck'd and you must re-mkswap your swap
+         partitions. It does not work with swap files.
 
          Right now you may boot without resuming and then later resume but
          in meantime you cannot use those swap partitions/files which were
index 312aa16..0f5dc71 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2003 Patrick Mochel
  * Copyright (c) 2003 Open Source Development Lab
+ * Copyright (c) 2004 Pavel Machek <pavel@suse.cz>
  *
  * This file is released under the GPLv2.
  *
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
+#include <linux/device.h>
 #include "power.h"
 
 
-extern u32 pm_disk_mode;
+extern suspend_disk_method_t pm_disk_mode;
 extern struct pm_ops * pm_ops;
 
 extern int swsusp_suspend(void);
@@ -41,7 +43,7 @@ char resume_file[256] = CONFIG_PM_STD_PARTITION;
  *     there ain't no turning back.
  */
 
-static int power_down(u32 mode)
+static void power_down(suspend_disk_method_t mode)
 {
        unsigned long flags;
        int error = 0;
@@ -67,7 +69,6 @@ static int power_down(u32 mode)
           after resume. */
        printk(KERN_CRIT "Please power me down manually\n");
        while(1);
-       return 0;
 }
 
 
@@ -85,10 +86,20 @@ static int in_suspend __nosavedata = 0;
 
 static void free_some_memory(void)
 {
-       printk("Freeing memory: ");
-       while (shrink_all_memory(10000))
-               printk(".");
-       printk("|\n");
+       unsigned int i = 0;
+       unsigned int tmp;
+       unsigned long pages = 0;
+       char *p = "-\\|/";
+
+       printk("Freeing memory...  ");
+       while ((tmp = shrink_all_memory(10000))) {
+               pages += tmp;
+               printk("\b%c", p[i]);
+               i++;
+               if (i > 3)
+                       i = 0;
+       }
+       printk("\bdone (%li pages freed)\n", pages);
 }
 
 
@@ -152,7 +163,7 @@ static int prepare(void)
  *
  *     If we're going through the firmware, then get it over with quickly.
  *
- *     If not, then call pmdis to do it's thing, then figure out how
+ *     If not, then call swsusp to do it's thing, then figure out how
  *     to power down the system.
  */
 
@@ -174,18 +185,9 @@ int pm_suspend_disk(void)
 
        if (in_suspend) {
                pr_debug("PM: writing image.\n");
-
-               /*
-                * FIXME: Leftover from swsusp. Are they necessary?
-                */
-               mb();
-               barrier();
-
                error = swsusp_write();
-               if (!error) {
-                       error = power_down(pm_disk_mode);
-                       pr_debug("PM: Power down failed.\n");
-               }
+               if (!error)
+                       power_down(pm_disk_mode);
        } else
                pr_debug("PM: Image restored successfully.\n");
        swsusp_free();
@@ -292,7 +294,7 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
        int i;
        int len;
        char *p;
-       u32 mode = 0;
+       suspend_disk_method_t mode = 0;
 
        p = memchr(buf, '\n', n);
        len = p ? p - buf : n;
index 2f08a43..0aefb03 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2003 Patrick Mochel
  * Copyright (c) 2003 Open Source Development Lab
  * 
- * This file is release under the GPLv2
+ * This file is released under the GPLv2
  *
  */
 
@@ -22,7 +22,7 @@
 DECLARE_MUTEX(pm_sem);
 
 struct pm_ops * pm_ops = NULL;
-u32 pm_disk_mode = PM_DISK_SHUTDOWN;
+suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
 
 /**
  *     pm_set_ops - Set the global power method table. 
@@ -46,7 +46,7 @@ void pm_set_ops(struct pm_ops * ops)
  *     the platform can enter the requested state.
  */
 
-static int suspend_prepare(u32 state)
+static int suspend_prepare(suspend_state_t state)
 {
        int error = 0;
 
@@ -102,7 +102,7 @@ static int suspend_enter(u32 state)
  *     console that we've allocated.
  */
 
-static void suspend_finish(u32 state)
+static void suspend_finish(suspend_state_t state)
 {
        device_resume();
        if (pm_ops && pm_ops->finish)
@@ -133,7 +133,7 @@ char * pm_states[] = {
  *     we've woken up).
  */
 
-static int enter_state(u32 state)
+static int enter_state(suspend_state_t state)
 {
        int error;
 
@@ -183,7 +183,7 @@ int software_suspend(void)
  *     structure, and enter (above).
  */
 
-int pm_suspend(u32 state)
+int pm_suspend(suspend_state_t state)
 {
        if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX)
                return enter_state(state);
@@ -221,7 +221,7 @@ static ssize_t state_show(struct subsystem * subsys, char * buf)
 
 static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
 {
-       u32 state = PM_SUSPEND_STANDBY;
+       suspend_state_t state = PM_SUSPEND_STANDBY;
        char ** s;
        char *p;
        int error;
index cab1476..ff62fa9 100644 (file)
@@ -1,5 +1,16 @@
 /*
  *  linux/kernel/profile.c
+ *  Simple profiling. Manages a direct-mapped profile hit count buffer,
+ *  with configurable resolution, support for restricting the cpus on
+ *  which profiling is done, and switching between cpu time and
+ *  schedule() calls via kernel command line parameters passed at boot.
+ *
+ *  Scheduler profiling support, Arjan van de Ven and Ingo Molnar,
+ *     Red Hat, July 2004
+ *  Consolidation of architecture support code for profiling,
+ *     William Irwin, Oracle, July 2004
+ *  Amortized hit count accounting via per-cpu open-addressed hashtables
+ *     to resolve timer interrupt livelocks, William Irwin, Oracle, 2004
  */
 
 #include <linux/config.h>
 #include <linux/notifier.h>
 #include <linux/mm.h>
 #include <linux/cpumask.h>
+#include <linux/cpu.h>
 #include <linux/profile.h>
+#include <linux/highmem.h>
 #include <asm/sections.h>
+#include <asm/semaphore.h>
+
+struct profile_hit {
+       u32 pc, hits;
+};
+#define PROFILE_GRPSHIFT       3
+#define PROFILE_GRPSZ          (1 << PROFILE_GRPSHIFT)
+#define NR_PROFILE_HIT         (PAGE_SIZE/sizeof(struct profile_hit))
+#define NR_PROFILE_GRP         (NR_PROFILE_HIT/PROFILE_GRPSZ)
+
+/* Oprofile timer tick hook */
+int (*timer_hook)(struct pt_regs *);
 
 static atomic_t *prof_buffer;
 static unsigned long prof_len, prof_shift;
 static int prof_on;
 static cpumask_t prof_cpu_mask = CPU_MASK_ALL;
+#ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits);
+static DEFINE_PER_CPU(int, cpu_profile_flip);
+static DECLARE_MUTEX(profile_flip_mutex);
+#endif /* CONFIG_SMP */
 
 static int __init profile_setup(char * str)
 {
        int par;
 
        if (!strncmp(str, "schedule", 8)) {
-               prof_on = 2;
+               prof_on = SCHED_PROFILING;
                printk(KERN_INFO "kernel schedule profiling enabled\n");
                if (str[7] == ',')
                        str += 8;
        }
        if (get_option(&str,&par)) {
                prof_shift = par;
-               prof_on = 1;
+               prof_on = CPU_PROFILING;
                printk(KERN_INFO "kernel profiling enabled (shift: %ld)\n",
                        prof_shift);
        }
@@ -141,38 +171,24 @@ int profile_event_unregister(enum profile_type type, struct notifier_block * n)
        return err;
 }
 
-static struct notifier_block * profile_listeners;
-static rwlock_t profile_lock = RW_LOCK_UNLOCKED;
-int register_profile_notifier(struct notifier_block * nb)
+int register_timer_hook(int (*hook)(struct pt_regs *))
 {
-       int err;
-       write_lock_irq(&profile_lock);
-       err = notifier_chain_register(&profile_listeners, nb);
-       write_unlock_irq(&profile_lock);
-       return err;
-}
-
-
-int unregister_profile_notifier(struct notifier_block * nb)
-{
-       int err;
-       write_lock_irq(&profile_lock);
-       err = notifier_chain_unregister(&profile_listeners, nb);
-       write_unlock_irq(&profile_lock);
-       return err;
+       if (timer_hook)
+               return -EBUSY;
+       timer_hook = hook;
+       return 0;
 }
 
-
-void profile_hook(struct pt_regs * regs)
+void unregister_timer_hook(int (*hook)(struct pt_regs *))
 {
-       read_lock(&profile_lock);
-       notifier_call_chain(&profile_listeners, 0, regs);
-       read_unlock(&profile_lock);
+       WARN_ON(hook != timer_hook);
+       timer_hook = NULL;
+       /* make sure all CPUs see the NULL hook */
+       synchronize_kernel();
 }
 
-EXPORT_SYMBOL_GPL(register_profile_notifier);
-EXPORT_SYMBOL_GPL(unregister_profile_notifier);
+EXPORT_SYMBOL_GPL(register_timer_hook);
+EXPORT_SYMBOL_GPL(unregister_timer_hook);
 EXPORT_SYMBOL_GPL(task_handoff_register);
 EXPORT_SYMBOL_GPL(task_handoff_unregister);
 
@@ -181,6 +197,179 @@ EXPORT_SYMBOL_GPL(task_handoff_unregister);
 EXPORT_SYMBOL_GPL(profile_event_register);
 EXPORT_SYMBOL_GPL(profile_event_unregister);
 
+#ifdef CONFIG_SMP
+/*
+ * Each cpu has a pair of open-addressed hashtables for pending
+ * profile hits. read_profile() IPI's all cpus to request them
+ * to flip buffers and flushes their contents to prof_buffer itself.
+ * Flip requests are serialized by the profile_flip_mutex. The sole
+ * use of having a second hashtable is for avoiding cacheline
+ * contention that would otherwise happen during flushes of pending
+ * profile hits required for the accuracy of reported profile hits
+ * and so resurrect the interrupt livelock issue.
+ *
+ * The open-addressed hashtables are indexed by profile buffer slot
+ * and hold the number of pending hits to that profile buffer slot on
+ * a cpu in an entry. When the hashtable overflows, all pending hits
+ * are accounted to their corresponding profile buffer slots with
+ * atomic_add() and the hashtable emptied. As numerous pending hits
+ * may be accounted to a profile buffer slot in a hashtable entry,
+ * this amortizes a number of atomic profile buffer increments likely
+ * to be far larger than the number of entries in the hashtable,
+ * particularly given that the number of distinct profile buffer
+ * positions to which hits are accounted during short intervals (e.g.
+ * several seconds) is usually very small. Exclusion from buffer
+ * flipping is provided by interrupt disablement (note that for
+ * SCHED_PROFILING profile_hit() may be called from process context).
+ * The hash function is meant to be lightweight as opposed to strong,
+ * and was vaguely inspired by ppc64 firmware-supported inverted
+ * pagetable hash functions, but uses a full hashtable full of finite
+ * collision chains, not just pairs of them.
+ *
+ * -- wli
+ */
+static void __profile_flip_buffers(void *unused)
+{
+       int cpu = smp_processor_id();
+
+       per_cpu(cpu_profile_flip, cpu) = !per_cpu(cpu_profile_flip, cpu);
+}
+
+static void profile_flip_buffers(void)
+{
+       int i, j, cpu;
+
+       down(&profile_flip_mutex);
+       j = per_cpu(cpu_profile_flip, get_cpu());
+       put_cpu();
+       on_each_cpu(__profile_flip_buffers, NULL, 0, 1);
+       for_each_online_cpu(cpu) {
+               struct profile_hit *hits = per_cpu(cpu_profile_hits, cpu)[j];
+               for (i = 0; i < NR_PROFILE_HIT; ++i) {
+                       if (!hits[i].hits) {
+                               if (hits[i].pc)
+                                       hits[i].pc = 0;
+                               continue;
+                       }
+                       atomic_add(hits[i].hits, &prof_buffer[hits[i].pc]);
+                       hits[i].hits = hits[i].pc = 0;
+               }
+       }
+       up(&profile_flip_mutex);
+}
+
+static void profile_discard_flip_buffers(void)
+{
+       int i, cpu;
+
+       down(&profile_flip_mutex);
+       i = per_cpu(cpu_profile_flip, get_cpu());
+       put_cpu();
+       on_each_cpu(__profile_flip_buffers, NULL, 0, 1);
+       for_each_online_cpu(cpu) {
+               struct profile_hit *hits = per_cpu(cpu_profile_hits, cpu)[i];
+               memset(hits, 0, NR_PROFILE_HIT*sizeof(struct profile_hit));
+       }
+       up(&profile_flip_mutex);
+}
+
+void profile_hit(int type, void *__pc)
+{
+       unsigned long primary, secondary, flags, pc = (unsigned long)__pc;
+       int i, j, cpu;
+       struct profile_hit *hits;
+
+       if (prof_on != type || !prof_buffer)
+               return;
+       pc = min((pc - (unsigned long)_stext) >> prof_shift, prof_len - 1);
+       i = primary = (pc & (NR_PROFILE_GRP - 1)) << PROFILE_GRPSHIFT;
+       secondary = (~(pc << 1) & (NR_PROFILE_GRP - 1)) << PROFILE_GRPSHIFT;
+       cpu = get_cpu();
+       hits = per_cpu(cpu_profile_hits, cpu)[per_cpu(cpu_profile_flip, cpu)];
+       if (!hits) {
+               put_cpu();
+               return;
+       }
+       local_irq_save(flags);
+       do {
+               for (j = 0; j < PROFILE_GRPSZ; ++j) {
+                       if (hits[i + j].pc == pc) {
+                               hits[i + j].hits++;
+                               goto out;
+                       } else if (!hits[i + j].hits) {
+                               hits[i + j].pc = pc;
+                               hits[i + j].hits = 1;
+                               goto out;
+                       }
+               }
+               i = (i + secondary) & (NR_PROFILE_HIT - 1);
+       } while (i != primary);
+       atomic_inc(&prof_buffer[pc]);
+       for (i = 0; i < NR_PROFILE_HIT; ++i) {
+               atomic_add(hits[i].hits, &prof_buffer[hits[i].pc]);
+               hits[i].pc = hits[i].hits = 0;
+       }
+out:
+       local_irq_restore(flags);
+       put_cpu();
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int __devinit profile_cpu_callback(struct notifier_block *info,
+                                       unsigned long action, void *__cpu)
+{
+       int node, cpu = (unsigned long)__cpu;
+       struct page *page;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+               node = cpu_to_node(cpu);
+               per_cpu(cpu_profile_flip, cpu) = 0;
+               if (!per_cpu(cpu_profile_hits, cpu)[1]) {
+                       page = alloc_pages_node(node, GFP_KERNEL, 0);
+                       if (!page)
+                               return NOTIFY_BAD;
+                       clear_highpage(page);
+                       per_cpu(cpu_profile_hits, cpu)[1] = page_address(page);
+               }
+               if (!per_cpu(cpu_profile_hits, cpu)[0]) {
+                       page = alloc_pages_node(node, GFP_KERNEL, 0);
+                       if (!page)
+                               goto out_free;
+                       clear_highpage(page);
+                       per_cpu(cpu_profile_hits, cpu)[0] = page_address(page);
+               }
+               break;
+       out_free:
+               page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
+               per_cpu(cpu_profile_hits, cpu)[1] = NULL;
+               __free_page(page);
+               return NOTIFY_BAD;
+       case CPU_ONLINE:
+               cpu_set(cpu, prof_cpu_mask);
+               break;
+       case CPU_UP_CANCELED:
+       case CPU_DEAD:
+               cpu_clear(cpu, prof_cpu_mask);
+               if (per_cpu(cpu_profile_hits, cpu)[0]) {
+                       page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
+                       per_cpu(cpu_profile_hits, cpu)[0] = NULL;
+                       __free_page(page);
+               }
+               if (per_cpu(cpu_profile_hits, cpu)[1]) {
+                       page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
+                       per_cpu(cpu_profile_hits, cpu)[1] = NULL;
+                       __free_page(page);
+               }
+               break;
+       }
+       return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+#else /* !CONFIG_SMP */
+#define profile_flip_buffers()         do { } while (0)
+#define profile_discard_flip_buffers() do { } while (0)
+
 void profile_hit(int type, void *__pc)
 {
        unsigned long pc;
@@ -190,11 +379,12 @@ void profile_hit(int type, void *__pc)
        pc = ((unsigned long)__pc - (unsigned long)_stext) >> prof_shift;
        atomic_inc(&prof_buffer[min(pc, prof_len - 1)]);
 }
+#endif /* !CONFIG_SMP */
 
 void profile_tick(int type, struct pt_regs *regs)
 {
-       if (type == CPU_PROFILING)
-               profile_hook(regs);
+       if (type == CPU_PROFILING && timer_hook)
+               timer_hook(regs);
        if (!user_mode(regs) && cpu_isset(smp_processor_id(), prof_cpu_mask))
                profile_hit(type, (void *)profile_pc(regs));
 }
@@ -256,6 +446,7 @@ read_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        char * pnt;
        unsigned int sample_step = 1 << prof_shift;
 
+       profile_flip_buffers();
        if (p >= (prof_len+1)*sizeof(unsigned int))
                return 0;
        if (count > (prof_len+1)*sizeof(unsigned int) - p)
@@ -296,7 +487,7 @@ static ssize_t write_profile(struct file *file, const char __user *buf,
                        return -EINVAL;
        }
 #endif
-
+       profile_discard_flip_buffers();
        memset(prof_buffer, 0, prof_len * sizeof(atomic_t));
        return count;
 }
@@ -306,16 +497,70 @@ static struct file_operations proc_profile_operations = {
        .write          = write_profile,
 };
 
+#ifdef CONFIG_SMP
+static void __init profile_nop(void *unused)
+{
+}
+
+static int __init create_hash_tables(void)
+{
+       int cpu;
+
+       for_each_online_cpu(cpu) {
+               int node = cpu_to_node(cpu);
+               struct page *page;
+
+               page = alloc_pages_node(node, GFP_KERNEL, 0);
+               if (!page)
+                       goto out_cleanup;
+               clear_highpage(page);
+               per_cpu(cpu_profile_hits, cpu)[1]
+                               = (struct profile_hit *)page_address(page);
+               page = alloc_pages_node(node, GFP_KERNEL, 0);
+               if (!page)
+                       goto out_cleanup;
+               clear_highpage(page);
+               per_cpu(cpu_profile_hits, cpu)[0]
+                               = (struct profile_hit *)page_address(page);
+       }
+       return 0;
+out_cleanup:
+       prof_on = 0;
+       mb();
+       on_each_cpu(profile_nop, NULL, 0, 1);
+       for_each_online_cpu(cpu) {
+               struct page *page;
+
+               if (per_cpu(cpu_profile_hits, cpu)[0]) {
+                       page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
+                       per_cpu(cpu_profile_hits, cpu)[0] = NULL;
+                       __free_page(page);
+               }
+               if (per_cpu(cpu_profile_hits, cpu)[1]) {
+                       page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
+                       per_cpu(cpu_profile_hits, cpu)[1] = NULL;
+                       __free_page(page);
+               }
+       }
+       return -1;
+}
+#else
+#define create_hash_tables()                   ({ 0; })
+#endif
+
 static int __init create_proc_profile(void)
 {
        struct proc_dir_entry *entry;
 
        if (!prof_on)
                return 0;
+       if (create_hash_tables())
+               return -1;
        if (!(entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL)))
                return 0;
        entry->proc_fops = &proc_profile_operations;
        entry->size = (1+prof_len) * sizeof(atomic_t);
+       hotcpu_notifier(profile_cpu_callback, 0);
        return 0;
 }
 module_init(create_proc_profile);
index 4a3f5c2..5f013dc 100644 (file)
@@ -57,6 +57,7 @@ static void *r_next(struct seq_file *m, void *v, loff_t *pos)
 }
 
 static void *r_start(struct seq_file *m, loff_t *pos)
+       __acquires(resource_lock)
 {
        struct resource *p = m->private;
        loff_t l = 0;
@@ -67,6 +68,7 @@ static void *r_start(struct seq_file *m, loff_t *pos)
 }
 
 static void r_stop(struct seq_file *m, void *v)
+       __releases(resource_lock)
 {
        read_unlock(&resource_lock);
 }
index 9610403..2ceea25 100644 (file)
@@ -52,7 +52,12 @@ static int stopmachine(void *cpu)
                        mb(); /* Must read state first. */
                        atomic_inc(&stopmachine_thread_ack);
                }
-               cpu_relax();
+               /* Yield in first stage: migration threads need to
+                * help our sisters onto their CPUs. */
+               if (!prepared && !irqs_disabled)
+                       yield();
+               else
+                       cpu_relax();
        }
 
        /* Ack: we are exiting. */
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);
index cd5d859..d9da4ec 100644 (file)
@@ -1,14 +1,14 @@
 
 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)
+       depends on (ALPHA || ARM || CRIS || H8300 || X86 || IA64 || M32R || 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)
+       depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || M32R || M68K || MIPS || PARISC || PPC32 || PPC64 || ARCH_S390 || SUPERH || SUPERH64 || SPARC32 || SPARC64 || X86_64 || USERMODE)
        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
@@ -28,17 +28,29 @@ config MAGIC_SYSRQ
          Enables console device to interpret special characters as
          commands to dump state information.
 
+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 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)
+       depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || M32R || 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.
+         memory. This can make kmalloc/kfree-intensive workloads much slower.
 
 config DEBUG_SPINLOCK
        bool "Spinlock debugging"
-       depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || MIPS || PPC32 || (SUPERH && !SUPERH64) || SPARC32 || SPARC64 || USERMODE || X86_64)
+       depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || M32R || MIPS || PARISC || 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
@@ -47,11 +59,18 @@ config DEBUG_SPINLOCK
 
 config DEBUG_SPINLOCK_SLEEP
        bool "Sleep-inside-spinlock checking"
-       depends on DEBUG_KERNEL && (X86 || IA64 || MIPS || PPC32 || PPC64 || ARCH_S390 || SPARC32 || SPARC64)
+       depends on DEBUG_KERNEL && (X86 || IA64 || M32R || MIPS || PPC32 || PPC64 || ARCH_S390 || SPARC32 || SPARC64 || USERMODE)
        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_KOBJECT
+       bool "kobject debugging"
+       depends on DEBUG_KERNEL
+       help
+         If you say Y here, some extra kobject debugging messages will be sent
+         to the syslog. 
+
 config DEBUG_HIGHMEM
        bool "Highmem debugging"
        depends on DEBUG_KERNEL && HIGHMEM && (X86 || PPC32 || MIPS || SPARC32)
@@ -61,7 +80,7 @@ config DEBUG_HIGHMEM
 
 config DEBUG_BUGVERBOSE
        bool "Verbose BUG() reporting (adds 70K)"
-       depends on DEBUG_KERNEL && (ARM || ARM26 || M68K || SPARC32 || SPARC64)
+       depends on DEBUG_KERNEL && (ARM || ARM26 || M32R || 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
@@ -69,7 +88,7 @@ config DEBUG_BUGVERBOSE
 
 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)
+       depends on DEBUG_KERNEL && (ALPHA || CRIS || X86 || IA64 || M32R || 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.
@@ -91,7 +110,7 @@ config DEBUG_INFO
 if !X86_64
 config FRAME_POINTER
        bool "Compile the kernel with frame pointers"
-       depends on X86 || CRIS || M68KNOMMU || PARISC
+       depends on X86 || CRIS || M68KNOMMU
        help
          If you say Y here the resulting kernel image will be slightly larger
          and slower, but it will give very useful debugging information.
index f84d160..6658d81 100644 (file)
@@ -27,7 +27,7 @@
  */
 
 #ifndef ATOMIC_DEC_AND_LOCK
-int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
        spin_lock(lock);
        if (atomic_dec_and_test(atomic))
@@ -36,5 +36,5 @@ int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
        return 0;
 }
 
-EXPORT_SYMBOL(atomic_dec_and_lock);
+EXPORT_SYMBOL(_atomic_dec_and_lock);
 #endif
index 6a9cac8..75e7d30 100644 (file)
@@ -118,6 +118,10 @@ static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #";
 #include "gzip.h"
 #define STATIC
 #endif /* !STATIC */
+
+#ifndef INIT
+#define INIT
+#endif
        
 #define slide window
 
@@ -139,15 +143,15 @@ struct huft {
 
 
 /* Function prototypes */
-STATIC int huft_build OF((unsigned *, unsigned, unsigned, 
+STATIC int INIT huft_build OF((unsigned *, unsigned, unsigned, 
                const ush *, const ush *, struct huft **, int *));
-STATIC int huft_free OF((struct huft *));
-STATIC int inflate_codes OF((struct huft *, struct huft *, int, int));
-STATIC int inflate_stored OF((void));
-STATIC int inflate_fixed OF((void));
-STATIC int inflate_dynamic OF((void));
-STATIC int inflate_block OF((int *));
-STATIC int inflate OF((void));
+STATIC int INIT huft_free OF((struct huft *));
+STATIC int INIT inflate_codes OF((struct huft *, struct huft *, int, int));
+STATIC int INIT inflate_stored OF((void));
+STATIC int INIT inflate_fixed OF((void));
+STATIC int INIT inflate_dynamic OF((void));
+STATIC int INIT inflate_block OF((int *));
+STATIC int INIT inflate OF((void));
 
 
 /* The inflate algorithm uses a sliding 32 K byte window on the uncompressed
@@ -272,7 +276,7 @@ STATIC const int dbits = 6;          /* bits in base distance lookup table */
 STATIC unsigned hufts;         /* track memory usage */
 
 
-STATIC int huft_build(
+STATIC int INIT huft_build(
        unsigned *b,            /* code lengths in bits (all assumed <= BMAX) */
        unsigned n,             /* number of codes (assumed <= N_MAX) */
        unsigned s,             /* number of simple-valued codes (0..s-1) */
@@ -491,7 +495,7 @@ DEBG("huft7 ");
 
 
 
-STATIC int huft_free(
+STATIC int INIT huft_free(
        struct huft *t         /* table to free */
        )
 /* Free the malloc'ed tables built by huft_build(), which makes a linked
@@ -513,7 +517,7 @@ STATIC int huft_free(
 }
 
 
-STATIC int inflate_codes(
+STATIC int INIT inflate_codes(
        struct huft *tl,    /* literal/length decoder tables */
        struct huft *td,    /* distance decoder tables */
        int bl,             /* number of bits decoded by tl[] */
@@ -628,7 +632,7 @@ STATIC int inflate_codes(
 
 
 
-STATIC int inflate_stored(void)
+STATIC int INIT inflate_stored(void)
 /* "decompress" an inflated type 0 (stored) block. */
 {
   unsigned n;           /* number of bytes in block */
@@ -689,7 +693,7 @@ DEBG("<stor");
 /*
  * We use `noinline' here to prevent gcc-3.5 from using too much stack space
  */
-STATIC int noinline inflate_fixed(void)
+STATIC int noinline INIT inflate_fixed(void)
 /* decompress an inflated type 1 (fixed Huffman codes) block.  We should
    either replace this with a custom decoder, or at least precompute the
    Huffman tables. */
@@ -745,7 +749,7 @@ DEBG("<fix");
 /*
  * We use `noinline' here to prevent gcc-3.5 from using too much stack space
  */
-STATIC int noinline inflate_dynamic(void)
+STATIC int noinline INIT inflate_dynamic(void)
 /* decompress an inflated type 2 (dynamic Huffman codes) block. */
 {
   int i;                /* temporary variables */
@@ -926,7 +930,7 @@ DEBG("dyn7 ");
 
 
 
-STATIC int inflate_block(
+STATIC int INIT inflate_block(
        int *e                  /* last block flag */
        )
 /* decompress an inflated block */
@@ -977,7 +981,7 @@ STATIC int inflate_block(
 
 
 
-STATIC int inflate(void)
+STATIC int INIT inflate(void)
 /* decompress an inflated entry */
 {
   int e;                /* last block flag */
@@ -1039,7 +1043,7 @@ static ulg crc;           /* initialized in makecrc() so it'll reside in bss */
  * gzip-1.0.3/makecrc.c.
  */
 
-static void
+static void INIT
 makecrc(void)
 {
 /* Not copyrighted 1990 Mark Adler     */
@@ -1087,7 +1091,7 @@ makecrc(void)
 /*
  * Do the uncompression!
  */
-static int gunzip(void)
+static int INIT gunzip(void)
 {
     uch flags;
     unsigned char magic[2]; /* magic header */
index d30ff1a..5e74390 100644 (file)
@@ -1,5 +1,7 @@
 /*
  * Implement the default iomap interfaces
+ *
+ * (C) Copyright 2004 Linus Torvalds
  */
 #include <linux/pci.h>
 #include <linux/module.h>
  *
  * Architectures for which this is not true can't use this generic
  * implementation and should do their own copy.
- *
+ */
+
+#ifndef HAVE_ARCH_PIO_SIZE
+/*
  * 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
@@ -27,6 +32,7 @@
 #define PIO_OFFSET     0x10000UL
 #define PIO_MASK       0x0ffffUL
 #define PIO_RESERVED   0x40000UL
+#endif
 
 /*
  * Ugly macros are a way of life.
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 */
index 761a57a..7ad2a48 100644 (file)
@@ -47,6 +47,7 @@ static int match_one(char *s, char *p, substring_t args[])
                else if (*p == '%') {
                        if (*s++ != '%')
                                return 0;
+                       p++;
                        continue;
                }
 
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");
+
index 8fe9c7e..f008d7c 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/nodemask.h>
 #include <linux/gfp.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -74,6 +75,7 @@
 #include <linux/init.h>
 #include <linux/compat.h>
 #include <linux/mempolicy.h>
+#include <asm/tlbflush.h>
 #include <asm/uaccess.h>
 
 static kmem_cache_t *policy_cache;
@@ -95,7 +97,7 @@ static int nodes_online(unsigned long *nodes)
 {
        DECLARE_BITMAP(online2, MAX_NUMNODES);
 
-       bitmap_copy(online2, node_online_map, MAX_NUMNODES);
+       bitmap_copy(online2, nodes_addr(node_online_map), MAX_NUMNODES);
        if (bitmap_empty(online2, MAX_NUMNODES))
                set_bit(0, online2);
        if (!bitmap_subset(nodes, online2, MAX_NUMNODES))
@@ -424,7 +426,7 @@ static void get_zonemask(struct mempolicy *p, unsigned long *nodes)
        case MPOL_PREFERRED:
                /* or use current node instead of online map? */
                if (p->v.preferred_node < 0)
-                       bitmap_copy(nodes, node_online_map, MAX_NUMNODES);
+                       bitmap_copy(nodes, nodes_addr(node_online_map), MAX_NUMNODES);
                else
                        __set_bit(p->v.preferred_node, nodes);
                break;
@@ -529,7 +531,7 @@ asmlinkage long sys_get_mempolicy(int __user *policy,
 
 #ifdef CONFIG_COMPAT
 
-asmlinkage long compat_get_mempolicy(int __user *policy,
+asmlinkage long compat_sys_get_mempolicy(int __user *policy,
                                     compat_ulong_t __user *nmask,
                                     compat_ulong_t maxnode,
                                     compat_ulong_t addr, compat_ulong_t flags)
@@ -557,7 +559,7 @@ asmlinkage long compat_get_mempolicy(int __user *policy,
        return err;
 }
 
-asmlinkage long compat_set_mempolicy(int mode, compat_ulong_t __user *nmask,
+asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
                                     compat_ulong_t maxnode)
 {
        long err = 0;
@@ -580,7 +582,7 @@ asmlinkage long compat_set_mempolicy(int mode, compat_ulong_t __user *nmask,
        return sys_set_mempolicy(mode, nm, nr_bits+1);
 }
 
-asmlinkage long compat_mbind(compat_ulong_t start, compat_ulong_t len,
+asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
                             compat_ulong_t mode, compat_ulong_t __user *nmask,
                             compat_ulong_t maxnode, compat_ulong_t flags)
 {
@@ -692,7 +694,7 @@ static struct page *alloc_page_interleave(unsigned gfp, unsigned order, unsigned
        struct zonelist *zl;
        struct page *page;
 
-       BUG_ON(!test_bit(nid, node_online_map));
+       BUG_ON(!node_online(nid));
        zl = NODE_DATA(nid)->node_zonelists + (gfp & GFP_ZONEMASK);
        page = __alloc_pages(gfp, order, zl);
        if (page && page_zone(page) == zl->zones[0]) {
@@ -886,12 +888,12 @@ int mpol_node_valid(int nid, struct vm_area_struct *vma, unsigned long addr)
  *
  * Remember policies even when nobody has shared memory mapped.
  * The policies are kept in Red-Black tree linked from the inode.
- * They are protected by the sp->sem semaphore, which should be held
+ * They are protected by the sp->lock spinlock, which should be held
  * for any accesses to the tree.
  */
 
 /* lookup first element intersecting start-end */
-/* Caller holds sp->sem */
+/* Caller holds sp->lock */
 static struct sp_node *
 sp_lookup(struct shared_policy *sp, unsigned long start, unsigned long end)
 {
@@ -899,13 +901,13 @@ sp_lookup(struct shared_policy *sp, unsigned long start, unsigned long end)
 
        while (n) {
                struct sp_node *p = rb_entry(n, struct sp_node, nd);
-               if (start >= p->end) {
+
+               if (start >= p->end)
                        n = n->rb_right;
-               } else if (end < p->start) {
+               else if (end <= p->start)
                        n = n->rb_left;
-               } else {
+               else
                        break;
-               }
        }
        if (!n)
                return NULL;
@@ -923,7 +925,7 @@ sp_lookup(struct shared_policy *sp, unsigned long start, unsigned long end)
 }
 
 /* Insert a new shared policy into the list. */
-/* Caller holds sp->sem */
+/* Caller holds sp->lock */
 static void sp_insert(struct shared_policy *sp, struct sp_node *new)
 {
        struct rb_node **p = &sp->root.rb_node;
@@ -953,13 +955,15 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx)
        struct mempolicy *pol = NULL;
        struct sp_node *sn;
 
-       down(&sp->sem);
+       if (!sp->root.rb_node)
+               return NULL;
+       spin_lock(&sp->lock);
        sn = sp_lookup(sp, idx, idx+1);
        if (sn) {
                mpol_get(sn->policy);
                pol = sn->policy;
        }
-       up(&sp->sem);
+       spin_unlock(&sp->lock);
        return pol;
 }
 
@@ -989,9 +993,10 @@ sp_alloc(unsigned long start, unsigned long end, struct mempolicy *pol)
 static int shared_policy_replace(struct shared_policy *sp, unsigned long start,
                                 unsigned long end, struct sp_node *new)
 {
-       struct sp_node *n, *new2;
+       struct sp_node *n, *new2 = NULL;
 
-       down(&sp->sem);
+restart:
+       spin_lock(&sp->lock);
        n = sp_lookup(sp, start, end);
        /* Take care of old policies in the same range. */
        while (n && n->start < end) {
@@ -1004,13 +1009,16 @@ static int shared_policy_replace(struct shared_policy *sp, unsigned long start,
                } else {
                        /* Old policy spanning whole new range. */
                        if (n->end > end) {
-                               new2 = sp_alloc(end, n->end, n->policy);
                                if (!new2) {
-                                       up(&sp->sem);
-                                       return -ENOMEM;
+                                       spin_unlock(&sp->lock);
+                                       new2 = sp_alloc(end, n->end, n->policy);
+                                       if (!new2)
+                                               return -ENOMEM;
+                                       goto restart;
                                }
                                n->end = end;
                                sp_insert(sp, new2);
+                               new2 = NULL;
                        }
                        /* Old crossing beginning, but not end (easy) */
                        if (n->start < start && n->end > start)
@@ -1022,7 +1030,11 @@ static int shared_policy_replace(struct shared_policy *sp, unsigned long start,
        }
        if (new)
                sp_insert(sp, new);
-       up(&sp->sem);
+       spin_unlock(&sp->lock);
+       if (new2) {
+               mpol_free(new2->policy);
+               kmem_cache_free(sn_cache, new2);
+       }
        return 0;
 }
 
@@ -1055,7 +1067,9 @@ void mpol_free_shared_policy(struct shared_policy *p)
        struct sp_node *n;
        struct rb_node *next;
 
-       down(&p->sem);
+       if (!p->root.rb_node)
+               return;
+       spin_lock(&p->lock);
        next = rb_first(&p->root);
        while (next) {
                n = rb_entry(next, struct sp_node, nd);
@@ -1064,7 +1078,7 @@ void mpol_free_shared_policy(struct shared_policy *p)
                mpol_free(n->policy);
                kmem_cache_free(sn_cache, n);
        }
-       up(&p->sem);
+       spin_unlock(&p->lock);
 }
 
 /* assumes fs == KERNEL_DS */
@@ -1081,7 +1095,8 @@ void __init numa_policy_init(void)
        /* Set interleaving policy for system init. This way not all
           the data structures allocated at system boot end up in node zero. */
 
-       if (sys_set_mempolicy(MPOL_INTERLEAVE, node_online_map, MAX_NUMNODES) < 0)
+       if (sys_set_mempolicy(MPOL_INTERLEAVE, nodes_addr(node_online_map),
+                                                       MAX_NUMNODES) < 0)
                printk("numa_policy_init: interleaving failed\n");
 }
 
index 7183937..985b6bb 100644 (file)
@@ -19,7 +19,11 @@ 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)
+#define SWAP_TOKEN_TIMEOUT     0
+/*
+ * Currently disabled; Needs further code to work at HZ * 300.
+ */
+unsigned long swap_token_default_timeout = SWAP_TOKEN_TIMEOUT;
 
 /*
  * Take the token away if the process had no page faults
@@ -75,10 +79,10 @@ void grab_swap_token(void)
                if ((reason = should_release_swap_token(mm))) {
                        unsigned long eligible = jiffies;
                        if (reason == SWAP_TOKEN_TIMED_OUT) {
-                               eligible += SWAP_TOKEN_TIMEOUT;
+                               eligible += swap_token_default_timeout;
                        }
                        mm->swap_token_time = eligible;
-                       swap_token_timeout = jiffies + SWAP_TOKEN_TIMEOUT;
+                       swap_token_timeout = jiffies + swap_token_default_timeout;
                        swap_token_mm = current->mm;
                }
                spin_unlock(&swap_token_lock);
index 90abc63..c13a216 100644 (file)
@@ -120,5 +120,3 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
 {
        return 0;
 }
-
-EXPORT_SYMBOL(shmem_file_setup);
index 066025f..752d77d 100644 (file)
@@ -166,3 +166,44 @@ unsigned short fddi_type_trans(struct sk_buff *skb, struct net_device *dev)
 }
 
 EXPORT_SYMBOL(fddi_type_trans);
+
+static int fddi_change_mtu(struct net_device *dev, int new_mtu)
+{
+       if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN))
+               return(-EINVAL);
+       dev->mtu = new_mtu;
+       return(0);
+}
+
+static void fddi_setup(struct net_device *dev)
+{
+       dev->change_mtu         = fddi_change_mtu;
+       dev->hard_header        = fddi_header;
+       dev->rebuild_header     = fddi_rebuild_header;
+
+       dev->type               = ARPHRD_FDDI;
+       dev->hard_header_len    = FDDI_K_SNAP_HLEN+3;   /* Assume 802.2 SNAP hdr len + 3 pad bytes */
+       dev->mtu                = FDDI_K_SNAP_DLEN;     /* Assume max payload of 802.2 SNAP frame */
+       dev->addr_len           = FDDI_K_ALEN;
+       dev->tx_queue_len       = 100;                  /* Long queues on FDDI */
+       dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
+       
+       memset(dev->broadcast, 0xFF, FDDI_K_ALEN);
+}
+
+/**
+ * alloc_fddidev - Register FDDI device
+ * @sizeof_priv: Size of additional driver-private structure to be allocated
+ *     for this FDDI device
+ *
+ * Fill in the fields of the device structure with FDDI-generic values.
+ *
+ * Constructs a new net device, complete with a private data area of
+ * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
+ * this private data area.
+ */
+struct net_device *alloc_fddidev(int sizeof_priv)
+{
+       return alloc_netdev(sizeof_priv, "fddi%d", fddi_setup);
+}
+EXPORT_SYMBOL(alloc_fddidev);
index 7ae2797..bb66e03 100644 (file)
@@ -154,3 +154,92 @@ unsigned short hippi_type_trans(struct sk_buff *skb, struct net_device *dev)
 }
 
 EXPORT_SYMBOL(hippi_type_trans);
+
+static int hippi_change_mtu(struct net_device *dev, int new_mtu)
+{
+       /*
+        * HIPPI's got these nice large MTUs.
+        */
+       if ((new_mtu < 68) || (new_mtu > 65280))
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       return(0);
+}
+
+/*
+ * For HIPPI we will actually use the lower 4 bytes of the hardware
+ * address as the I-FIELD rather than the actual hardware address.
+ */
+static int hippi_mac_addr(struct net_device *dev, void *p)
+{
+       struct sockaddr *addr = p;
+       if (netif_running(dev))
+               return -EBUSY;
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+       return 0;
+}
+
+static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
+{
+       /* Never send broadcast/multicast ARP messages */
+       p->mcast_probes = 0;
+       /* In IPv6 unicast probes are valid even on NBMA,
+       * because they are encapsulated in normal IPv6 protocol.
+       * Should be a generic flag. 
+       */
+       if (p->tbl->family != AF_INET6)
+               p->ucast_probes = 0;
+       return 0;
+}
+
+static void hippi_setup(struct net_device *dev)
+{
+       dev->set_multicast_list         = NULL;
+       dev->change_mtu                 = hippi_change_mtu;
+       dev->hard_header                = hippi_header;
+       dev->rebuild_header             = hippi_rebuild_header;
+       dev->set_mac_address            = hippi_mac_addr;
+       dev->hard_header_parse          = NULL;
+       dev->hard_header_cache          = NULL;
+       dev->header_cache_update        = NULL;
+       dev->neigh_setup                = hippi_neigh_setup_dev; 
+
+       /*
+        * We don't support HIPPI `ARP' for the time being, and probably
+        * never will unless someone else implements it. However we
+        * still need a fake ARPHRD to make ifconfig and friends play ball.
+        */
+       dev->type               = ARPHRD_HIPPI;
+       dev->hard_header_len    = HIPPI_HLEN;
+       dev->mtu                = 65280;
+       dev->addr_len           = HIPPI_ALEN;
+       dev->tx_queue_len       = 25 /* 5 */;
+       memset(dev->broadcast, 0xFF, HIPPI_ALEN);
+
+
+       /*
+        * HIPPI doesn't support broadcast+multicast and we only use
+        * static ARP tables. ARP is disabled by hippi_neigh_setup_dev. 
+        */
+       dev->flags = 0; 
+}
+
+/**
+ * alloc_hippi_dev - Register HIPPI device
+ * @sizeof_priv: Size of additional driver-private structure to be allocated
+ *     for this HIPPI device
+ *
+ * Fill in the fields of the device structure with HIPPI-generic values.
+ *
+ * Constructs a new net device, complete with a private data area of
+ * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
+ * this private data area.
+ */
+
+struct net_device *alloc_hippi_dev(int sizeof_priv)
+{
+       return alloc_netdev(sizeof_priv, "hip%d", hippi_setup);
+}
+
+EXPORT_SYMBOL(alloc_hippi_dev);
index d179728..5cda56e 100644 (file)
@@ -4,6 +4,6 @@
 
 obj-$(CONFIG_ATALK) += appletalk.o
 
-appletalk-y                    := aarp.o ddp.o
+appletalk-y                    := aarp.o ddp.o dev.o
 appletalk-$(CONFIG_PROC_FS)    += atalk_proc.o
 appletalk-$(CONFIG_SYSCTL)     += sysctl_net_atalk.o
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);
index ba4a156..a28db2d 100644 (file)
@@ -267,8 +267,8 @@ static struct mpoa_client *alloc_mpc(void)
        if (mpc == NULL)
                return NULL;
        memset(mpc, 0, sizeof(struct mpoa_client));
-       mpc->ingress_lock = RW_LOCK_UNLOCKED;
-       mpc->egress_lock  = RW_LOCK_UNLOCKED;
+       rwlock_init(&mpc->ingress_lock);
+       rwlock_init(&mpc->egress_lock);
        mpc->next = mpcs;
        atm_mpoa_init_cache(mpc);
 
@@ -755,13 +755,18 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
 {
        struct mpoa_client *mpc;
        struct lec_priv *priv;
+       int err;
        
        if (mpcs == NULL) {
                init_timer(&mpc_timer);
                mpc_timer_refresh();
 
                /* This lets us now how our LECs are doing */
-               register_netdevice_notifier(&mpoa_notifier);
+               err = register_netdevice_notifier(&mpoa_notifier);
+               if (err < 0) {
+                       del_timer(&mpc_timer);
+                       return err;
+               }
        }
        
        mpc = find_mpc_by_itfnum(arg);
index 7e03820..18d9b73 100644 (file)
@@ -493,7 +493,6 @@ static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
        application = cmtp_application_get(session, CMTP_APPLID, appl);
        if ((!application) || (application->state != BT_CONNECTED)) {
                BT_ERR("Can't find application with id %d", appl);
-               kfree_skb(skb);
                return CAPI_ILLAPPNR;
        }
 
index ed8abef..08907d3 100644 (file)
@@ -645,32 +645,26 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
        rfcomm_dev_put(dev);
 }
 
-static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
+static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
        struct rfcomm_dlc *dlc = dev->dlc;
        struct sk_buff *skb;
        int err = 0, sent = 0, size;
 
-       BT_DBG("tty %p from_user %d count %d", tty, from_user, count);
+       BT_DBG("tty %p count %d", tty, count);
 
        while (count) {
                size = min_t(uint, count, dlc->mtu);
 
-               if (from_user)
-                       skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_KERNEL);
-               else
-                       skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
+               skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
                
                if (!skb)
                        break;
 
                skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
 
-               if (from_user)
-                       copy_from_user(skb_put(skb, size), buf + sent, size);
-               else
-                       memcpy(skb_put(skb, size), buf + sent, size);
+               memcpy(skb_put(skb, size), buf + sent, size);
 
                if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {
                        kfree_skb(skb);
index 50e4df3..b240ad4 100644 (file)
@@ -197,7 +197,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
                skb_pull(skb, VLAN_HLEN);
                skb->nh.raw += VLAN_HLEN;
        }
-       skb->dst->output(&skb);
+       skb->dst->output(skb);
        return 0;
 }
 
index e8ce25b..db098ff 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/module.h> 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
index 866f292..f05fde9 100644 (file)
@@ -452,9 +452,23 @@ static int ethtool_get_tx_csum(struct net_device *dev, char __user *useraddr)
        return 0;
 }
 
+static int __ethtool_set_sg(struct net_device *dev, u32 data)
+{
+       int err;
+
+       if (!data && dev->ethtool_ops->set_tso) {
+               err = dev->ethtool_ops->set_tso(dev, 0);
+               if (err)
+                       return err;
+       }
+
+       return dev->ethtool_ops->set_sg(dev, data);
+}
+
 static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
 {
        struct ethtool_value edata;
+       int err;
 
        if (!dev->ethtool_ops->set_tx_csum)
                return -EOPNOTSUPP;
@@ -462,6 +476,12 @@ static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
                return -EFAULT;
 
+       if (!edata.data && dev->ethtool_ops->set_sg) {
+               err = __ethtool_set_sg(dev, 0);
+               if (err)
+                       return err;
+       }
+
        return dev->ethtool_ops->set_tx_csum(dev, edata.data);
 }
 
@@ -489,7 +509,13 @@ static int ethtool_set_sg(struct net_device *dev, char __user *useraddr)
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
                return -EFAULT;
 
-       return dev->ethtool_ops->set_sg(dev, edata.data);
+       if (edata.data && 
+           !(dev->features & (NETIF_F_IP_CSUM |
+                              NETIF_F_NO_CSUM |
+                              NETIF_F_HW_CSUM)))
+               return -EINVAL;
+
+       return __ethtool_set_sg(dev, edata.data);
 }
 
 static int ethtool_get_tso(struct net_device *dev, char __user *useraddr)
@@ -516,6 +542,9 @@ static int ethtool_set_tso(struct net_device *dev, char __user *useraddr)
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
                return -EFAULT;
 
+       if (edata.data && !(dev->features & NETIF_F_SG))
+               return -EINVAL;
+
        return dev->ethtool_ops->set_tso(dev, edata.data);
 }
 
index 4d65f93..c9c70c6 100644 (file)
@@ -132,6 +132,21 @@ static void est_timer(unsigned long arg)
        read_unlock(&est_lock);
 }
 
+/**
+ * gen_new_estimator - create a new rate estimator
+ * @bstats: basic statistics
+ * @rate_est: rate estimator statistics
+ * @stats_lock: statistics lock
+ * @opt: rate estimator configuration TLV
+ *
+ * Creates a new rate estimator with &bstats as source and &rate_est
+ * as destination. A new timer with the interval specified in the
+ * configuration TLV is created. Upon each interval, the latest statistics
+ * will be read from &bstats and the estimated rate will be stored in
+ * &rate_est with the statistics lock grabed during this period.
+ * 
+ * Returns 0 on success or a negative error code.
+ */
 int gen_new_estimator(struct gnet_stats_basic *bstats,
        struct gnet_stats_rate_est *rate_est, spinlock_t *stats_lock, struct rtattr *opt)
 {
@@ -173,6 +188,14 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
        return 0;
 }
 
+/**
+ * gen_kill_estimator - remove a rate estimator
+ * @bstats: basic statistics
+ * @rate_est: rate estimator statistics
+ *
+ * Removes the rate estimator specified by &bstats and &rate_est
+ * and deletes the timer.
+ */
 void gen_kill_estimator(struct gnet_stats_basic *bstats,
        struct gnet_stats_rate_est *rate_est)
 {
@@ -200,5 +223,28 @@ void gen_kill_estimator(struct gnet_stats_basic *bstats,
        }
 }
 
+/**
+ * gen_replace_estimator - replace rate estimator configruation
+ * @bstats: basic statistics
+ * @rate_est: rate estimator statistics
+ * @stats_lock: statistics lock
+ * @opt: rate estimator configuration TLV
+ *
+ * Replaces the configuration of a rate estimator by calling
+ * gen_kill_estimator() and gen_new_estimator().
+ * 
+ * Returns 0 on success or a negative error code.
+ */
+int
+gen_replace_estimator(struct gnet_stats_basic *bstats,
+       struct gnet_stats_rate_est *rate_est, spinlock_t *stats_lock,
+       struct rtattr *opt)
+{
+    gen_kill_estimator(bstats, rate_est);
+    return gen_new_estimator(bstats, rate_est, stats_lock, opt);
+}
+    
+
 EXPORT_SYMBOL(gen_kill_estimator);
 EXPORT_SYMBOL(gen_new_estimator);
+EXPORT_SYMBOL(gen_replace_estimator);
index 2b2ba65..86cd889 100644 (file)
@@ -34,6 +34,24 @@ rtattr_failure:
        return -1;
 }
 
+/**
+ * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
+ * @skb: socket buffer to put statistics TLVs into
+ * @type: TLV type for top level statistic TLV
+ * @tc_stats_type: TLV type for backward compatibility struct tc_stats TLV
+ * @xstats_type: TLV type for backward compatibility xstats TLV
+ * @lock: statistics lock
+ * @d: dumping handle
+ *
+ * Initializes the dumping handle, grabs the statistic lock and appends
+ * an empty TLV header to the socket buffer for use a container for all
+ * other statistic TLVS.
+ *
+ * The dumping handle is marked to be in backward compatibility mode telling
+ * all gnet_stats_copy_XXX() functions to fill a local copy of struct tc_stats.
+ *
+ * Returns 0 on success or -1 if the room in the socket buffer was not sufficient.
+ */
 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)
@@ -52,6 +70,19 @@ gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type,
        return gnet_stats_copy(d, type, NULL, 0);
 }
 
+/**
+ * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
+ * @skb: socket buffer to put statistics TLVs into
+ * @type: TLV type for top level statistic TLV
+ * @lock: statistics lock
+ * @d: dumping handle
+ *
+ * Initializes the dumping handle, grabs the statistic lock and appends
+ * an empty TLV header to the socket buffer for use a container for all
+ * other statistic TLVS.
+ *
+ * Returns 0 on success or -1 if the room in the socket buffer was not sufficient.
+ */
 int
 gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,
        struct gnet_dump *d)
@@ -59,7 +90,17 @@ gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,
        return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d);
 }
 
-
+/**
+ * gnet_stats_copy_basic - copy basic statistics into statistic TLV
+ * @d: dumping handle
+ * @b: basic statistics
+ *
+ * Appends the basic statistics to the top level TLV created by
+ * gnet_stats_start_copy().
+ *
+ * Returns 0 on success or -1 with the statistic lock released
+ * if the room in the socket buffer was not sufficient.
+ */
 int
 gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic *b)
 {
@@ -71,6 +112,17 @@ gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic *b)
        return gnet_stats_copy(d, TCA_STATS_BASIC, b, sizeof(*b));
 }
 
+/**
+ * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
+ * @d: dumping handle
+ * @r: rate estimator statistics
+ *
+ * Appends the rate estimator statistics to the top level TLV created by
+ * gnet_stats_start_copy().
+ *
+ * Returns 0 on success or -1 with the statistic lock released
+ * if the room in the socket buffer was not sufficient.
+ */
 int
 gnet_stats_copy_rate_est(struct gnet_dump *d, struct gnet_stats_rate_est *r)
 {
@@ -82,6 +134,17 @@ gnet_stats_copy_rate_est(struct gnet_dump *d, struct gnet_stats_rate_est *r)
        return gnet_stats_copy(d, TCA_STATS_RATE_EST, r, sizeof(*r));
 }
 
+/**
+ * gnet_stats_copy_queue - copy queue statistics into statistics TLV
+ * @d: dumping handle
+ * @q: queue statistics
+ *
+ * Appends the queue statistics to the top level TLV created by
+ * gnet_stats_start_copy().
+ *
+ * Returns 0 on success or -1 with the statistic lock released
+ * if the room in the socket buffer was not sufficient.
+ */
 int
 gnet_stats_copy_queue(struct gnet_dump *d, struct gnet_stats_queue *q)
 {
@@ -95,6 +158,19 @@ gnet_stats_copy_queue(struct gnet_dump *d, struct gnet_stats_queue *q)
        return gnet_stats_copy(d, TCA_STATS_QUEUE, q, sizeof(*q));
 }
 
+/**
+ * gnet_stats_copy_app - copy application specific statistics into statistics TLV
+ * @d: dumping handle
+ * @st: application specific statistics data
+ * @len: length of data
+ *
+ * Appends the application sepecific statistics to the top level TLV created by
+ * gnet_stats_start_copy() and remembers the data for XSTATS if the dumping
+ * handle is in backward compatibility mode.
+ *
+ * Returns 0 on success or -1 with the statistic lock released
+ * if the room in the socket buffer was not sufficient.
+ */
 int
 gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
 {
@@ -103,6 +179,18 @@ gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
        return gnet_stats_copy(d, TCA_STATS_APP, st, len);
 }
 
+/**
+ * gnet_stats_finish_copy - finish dumping procedure
+ * @d: dumping handle
+ *
+ * Corrects the length of the top level TLV to include all TLVs added
+ * by gnet_stats_copy_XXX() calls. Adds the backward compatibility TLVs
+ * if gnet_stats_start_copy_compat() was used and releases the statistics
+ * lock.
+ *
+ * Returns 0 on success or -1 with the statistic lock released
+ * if the room in the socket buffer was not sufficient.
+ */
 int
 gnet_stats_finish_copy(struct gnet_dump *d)
 {
@@ -125,6 +213,7 @@ gnet_stats_finish_copy(struct gnet_dump *d)
 
 
 EXPORT_SYMBOL(gnet_stats_start_copy);
+EXPORT_SYMBOL(gnet_stats_start_copy_compat);
 EXPORT_SYMBOL(gnet_stats_copy_basic);
 EXPORT_SYMBOL(gnet_stats_copy_rate_est);
 EXPORT_SYMBOL(gnet_stats_copy_queue);
index 6dd61ea..0a84b0d 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/types.h>
 
 
index 731eec6..e6d85cf 100644 (file)
@@ -2,7 +2,7 @@
  * This file implement the Wireless Extensions APIs.
  *
  * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
  *
  * (As all part of the Linux kernel, this file is GPL)
  */
  *     o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
  *     o Add enhanced spy support : iw_handler_set_thrspy() and event.
  *     o Add WIRELESS_EXT version display in /proc/net/wireless
+ *
+ * v6 - 18.06.04 - Jean II
+ *     o Change get_spydata() method for added safety
+ *     o Remove spy #ifdef, they are always on -> cleaner code
+ *     o Allow any size GET request if user specifies length > max
+ *             and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
+ *     o Start migrating get_wireless_stats to struct iw_handler_def
+ *     o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
+ * Based on patch from Pavel Roskin <proski@gnu.org> :
+ *     o Fix kernel data leak to user space in private handler handling
  */
 
 /***************************** INCLUDES *****************************/
 
 /**************************** CONSTANTS ****************************/
 
-/* Enough lenience, let's make sure things are proper... */
-#define WE_STRICT_WRITE                /* Check write buffer size */
-/* I'll probably drop both the define and kernel message in the next version */
-
 /* Debugging stuff */
 #undef WE_IOCTL_DEBUG          /* Debug IOCTL API */
 #undef WE_EVENT_DEBUG          /* Debug Event dispatcher */
@@ -186,6 +192,7 @@ static const struct iw_ioctl_description standard_ioctl[] = {
                .token_size     = sizeof(struct sockaddr) +
                                  sizeof(struct iw_quality),
                .max_tokens     = IW_MAX_AP,
+               .flags          = IW_DESCR_FLAG_NOMAX,
        },
        [SIOCSIWSCAN    - SIOCIWFIRST] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
@@ -194,6 +201,7 @@ static const struct iw_ioctl_description standard_ioctl[] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_SCAN_MAX_DATA,
+               .flags          = IW_DESCR_FLAG_NOMAX,
        },
        [SIOCSIWESSID   - SIOCIWFIRST] = {
                .header_type    = IW_HEADER_TYPE_POINT,
@@ -296,7 +304,7 @@ static const int standard_event_num = (sizeof(standard_event) /
                                       sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
-static const char priv_type_size[] = {
+const char iw_priv_type_size[] = {
        0,                              /* IW_PRIV_TYPE_NONE */
        1,                              /* IW_PRIV_TYPE_BYTE */
        1,                              /* IW_PRIV_TYPE_CHAR */
@@ -363,12 +371,15 @@ static inline iw_handler get_handler(struct net_device *dev,
  */
 static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
 {
+       /* New location */
+       if((dev->wireless_handlers != NULL) &&
+          (dev->wireless_handlers->get_wireless_stats != NULL))
+               return dev->wireless_handlers->get_wireless_stats(dev);
+
+       /* Old location, will be phased out in next WE */
        return (dev->get_wireless_stats ?
                dev->get_wireless_stats(dev) :
                (struct iw_statistics *) NULL);
-       /* In the future, get_wireless_stats may move from 'struct net_device'
-        * to 'struct iw_handler_def', to de-bloat struct net_device.
-        * Definitely worse a thought... */
 }
 
 /* ---------------------------------------------------------------- */
@@ -403,14 +414,32 @@ static inline int call_commit_handler(struct net_device * dev)
 
 /* ---------------------------------------------------------------- */
 /*
- * Number of private arguments
+ * Calculate size of private arguments
  */
 static inline int get_priv_size(__u16  args)
 {
        int     num = args & IW_PRIV_SIZE_MASK;
        int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
 
-       return num * priv_type_size[type];
+       return num * iw_priv_type_size[type];
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Re-calculate the size of private arguments
+ */
+static inline int adjust_priv_size(__u16               args,
+                                  union iwreq_data *   wrqu)
+{
+       int     num = wrqu->data.length;
+       int     max = args & IW_PRIV_SIZE_MASK;
+       int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+       /* Make sure the driver doesn't goof up */
+       if (max < num)
+               num = max;
+
+       return num * iw_priv_type_size[type];
 }
 
 
@@ -440,11 +469,14 @@ static __inline__ void wireless_seq_printf_stats(struct seq_file *seq,
                seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
                                "%6d %6d   %6d\n",
                           dev->name, stats->status, stats->qual.qual,
-                          stats->qual.updated & 1 ? '.' : ' ',
+                          stats->qual.updated & IW_QUAL_QUAL_UPDATED
+                          ? '.' : ' ',
                           ((__u8) stats->qual.level),
-                          stats->qual.updated & 2 ? '.' : ' ',
+                          stats->qual.updated & IW_QUAL_LEVEL_UPDATED
+                          ? '.' : ' ',
                           ((__u8) stats->qual.noise),
-                          stats->qual.updated & 4 ? '.' : ' ',
+                          stats->qual.updated & IW_QUAL_NOISE_UPDATED
+                          ? '.' : ' ',
                           stats->discard.nwid, stats->discard.code,
                           stats->discard.fragment, stats->discard.retries,
                           stats->discard.misc, stats->miss.beacon);
@@ -555,13 +587,15 @@ static inline int ioctl_export_private(struct net_device *        dev,
        /* Check NULL pointer */
        if(iwr->u.data.pointer == NULL)
                return -EFAULT;
-#ifdef WE_STRICT_WRITE
+
        /* Check if there is enough buffer up there */
        if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
-               printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
+               /* User space can't know in advance how large the buffer
+                * needs to be. Give it a hint, so that we can support
+                * any size buffer we want somewhat efficiently... */
+               iwr->u.data.length = dev->wireless_handlers->num_private_args;
                return -E2BIG;
        }
-#endif /* WE_STRICT_WRITE */
 
        /* Set the number of available ioctls. */
        iwr->u.data.length = dev->wireless_handlers->num_private_args;
@@ -590,7 +624,6 @@ static inline int ioctl_standard_call(struct net_device *   dev,
        const struct iw_ioctl_description *     descr;
        struct iw_request_info                  info;
        int                                     ret = -EINVAL;
-       int                                     user_size = 0;
 
        /* Get the description of the IOCTL */
        if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
@@ -621,8 +654,14 @@ static inline int ioctl_standard_call(struct net_device *  dev,
 #endif /* WE_SET_EVENT */
        } else {
                char *  extra;
+               int     extra_size;
+               int     user_length = 0;
                int     err;
 
+               /* Calculate space needed by arguments. Always allocate
+                * for max space. Easier, and won't last long... */
+               extra_size = descr->max_tokens * descr->token_size;
+
                /* Check what user space is giving us */
                if(IW_IS_SET(cmd)) {
                        /* Check NULL pointer */
@@ -639,18 +678,33 @@ static inline int ioctl_standard_call(struct net_device * dev,
                        if(iwr->u.data.pointer == NULL)
                                return -EFAULT;
                        /* Save user space buffer size for checking */
-                       user_size = iwr->u.data.length;
+                       user_length = iwr->u.data.length;
+
+                       /* Don't check if user_length > max to allow forward
+                        * compatibility. The test user_length < min is
+                        * implied by the test at the end. */
+
+                       /* Support for very large requests */
+                       if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
+                          (user_length > descr->max_tokens)) {
+                               /* Allow userspace to GET more than max so
+                                * we can support any size GET requests.
+                                * There is still a limit : -ENOMEM. */
+                               extra_size = user_length * descr->token_size;
+                               /* Note : user_length is originally a __u16,
+                                * and token_size is controlled by us,
+                                * so extra_size won't get negative and
+                                * won't overflow... */
+                       }
                }
 
 #ifdef WE_IOCTL_DEBUG
                printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
-                      dev->name, descr->max_tokens * descr->token_size);
+                      dev->name, extra_size);
 #endif /* WE_IOCTL_DEBUG */
 
-               /* Always allocate for max space. Easier, and won't last
-                * long... */
-               extra = kmalloc(descr->max_tokens * descr->token_size,
-                               GFP_KERNEL);
+               /* Create the kernel buffer */
+               extra = kmalloc(extra_size, GFP_KERNEL);
                if (extra == NULL) {
                        return -ENOMEM;
                }
@@ -676,14 +730,11 @@ static inline int ioctl_standard_call(struct net_device * dev,
 
                /* If we have something to return to the user */
                if (!ret && IW_IS_GET(cmd)) {
-#ifdef WE_STRICT_WRITE
                        /* Check if there is enough buffer up there */
-                       if(user_size < iwr->u.data.length) {
-                               printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
+                       if(user_length < iwr->u.data.length) {
                                kfree(extra);
                                return -E2BIG;
                        }
-#endif /* WE_STRICT_WRITE */
 
                        err = copy_to_user(iwr->u.data.pointer, extra,
                                           iwr->u.data.length *
@@ -746,7 +797,7 @@ static inline int ioctl_private_call(struct net_device *    dev,
                                     iw_handler         handler)
 {
        struct iwreq *                  iwr = (struct iwreq *) ifr;
-       struct iw_priv_args *           descr = NULL;
+       const struct iw_priv_args *     descr = NULL;
        struct iw_request_info          info;
        int                             extra_size = 0;
        int                             i;
@@ -786,7 +837,7 @@ static inline int ioctl_private_call(struct net_device *    dev,
                           ((extra_size + offset) <= IFNAMSIZ))
                                extra_size = 0;
                } else {
-                       /* Size of set arguments */
+                       /* Size of get arguments */
                        extra_size = get_priv_size(descr->get_args);
 
                        /* Does it fits in iwr ? */
@@ -856,6 +907,14 @@ static inline int ioctl_private_call(struct net_device *   dev,
 
                /* If we have something to return to the user */
                if (!ret && IW_IS_GET(cmd)) {
+
+                       /* Adjust for the actual length if it's variable,
+                        * avoid leaking kernel bits outside. */
+                       if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
+                               extra_size = adjust_priv_size(descr->get_args,
+                                                             &(iwr->u));
+                       }
+
                        err = copy_to_user(iwr->u.data.pointer, extra,
                                           extra_size);
                        if (err)
@@ -1127,9 +1186,25 @@ void wireless_send_event(struct net_device *     dev,
  * One of the main advantage of centralising spy support here is that
  * it becomes much easier to improve and extend it without having to touch
  * the drivers. One example is the addition of the Spy-Threshold events.
- * Note : IW_WIRELESS_SPY is defined in iw_handler.h
  */
 
+/* ---------------------------------------------------------------- */
+/*
+ * Return the pointer to the spy data in the driver.
+ * Because this is called on the Rx path via wireless_spy_update(),
+ * we want it to be efficient...
+ */
+static inline struct iw_spy_data * get_spydata(struct net_device *dev)
+{
+       /* This is the new way */
+       if(dev->wireless_data)
+               return(dev->wireless_data->spy_data);
+
+       /* This is the old way. Doesn't work for multi-headed drivers.
+        * It will be removed in the next version of WE. */
+       return (dev->priv + dev->wireless_handlers->spy_offset);
+}
+
 /*------------------------------------------------------------------*/
 /*
  * Standard Wireless Handler : set Spy List
@@ -1139,16 +1214,30 @@ int iw_handler_set_spy(struct net_device *      dev,
                       union iwreq_data *       wrqu,
                       char *                   extra)
 {
-#ifdef IW_WIRELESS_SPY
-       struct iw_spy_data *    spydata = (dev->priv +
-                                          dev->wireless_handlers->spy_offset);
+       struct iw_spy_data *    spydata = get_spydata(dev);
        struct sockaddr *       address = (struct sockaddr *) extra;
 
+       if(!dev->wireless_data)
+               /* Help user know that driver needs updating */
+               printk(KERN_DEBUG "%s (WE) : Driver using old/buggy spy support, please fix driver !\n",
+                      dev->name);
+       /* Make sure driver is not buggy or using the old API */
+       if(!spydata)
+               return -EOPNOTSUPP;
+
        /* Disable spy collection while we copy the addresses.
-        * As we don't disable interrupts, we need to do this to avoid races.
-        * As we are the only writer, this is good enough. */
+        * While we copy addresses, any call to wireless_spy_update()
+        * will NOP. This is OK, as anyway the addresses are changing. */
        spydata->spy_number = 0;
 
+       /* We want to operate without locking, because wireless_spy_update()
+        * most likely will happen in the interrupt handler, and therefore
+        * have its own locking constraints and needs performance.
+        * The rtnl_lock() make sure we don't race with the other iw_handlers.
+        * This make sure wireless_spy_update() "see" that the spy list
+        * is temporarily disabled. */
+       wmb();
+
        /* Are there are addresses to copy? */
        if(wrqu->data.length > 0) {
                int i;
@@ -1174,13 +1263,14 @@ int iw_handler_set_spy(struct net_device *      dev,
                               spydata->spy_address[i][5]);
 #endif /* WE_SPY_DEBUG */
        }
+
+       /* Make sure above is updated before re-enabling */
+       wmb();
+
        /* Enable addresses */
        spydata->spy_number = wrqu->data.length;
 
        return 0;
-#else /* IW_WIRELESS_SPY */
-       return -EOPNOTSUPP;
-#endif /* IW_WIRELESS_SPY */
 }
 
 /*------------------------------------------------------------------*/
@@ -1192,12 +1282,14 @@ int iw_handler_get_spy(struct net_device *      dev,
                       union iwreq_data *       wrqu,
                       char *                   extra)
 {
-#ifdef IW_WIRELESS_SPY
-       struct iw_spy_data *    spydata = (dev->priv +
-                                          dev->wireless_handlers->spy_offset);
+       struct iw_spy_data *    spydata = get_spydata(dev);
        struct sockaddr *       address = (struct sockaddr *) extra;
        int                     i;
 
+       /* Make sure driver is not buggy or using the old API */
+       if(!spydata)
+               return -EOPNOTSUPP;
+
        wrqu->data.length = spydata->spy_number;
 
        /* Copy addresses. */
@@ -1214,9 +1306,6 @@ int iw_handler_get_spy(struct net_device *        dev,
        for(i = 0; i < spydata->spy_number; i++)
                spydata->spy_stat[i].updated = 0;
        return 0;
-#else /* IW_WIRELESS_SPY */
-       return -EOPNOTSUPP;
-#endif /* IW_WIRELESS_SPY */
 }
 
 /*------------------------------------------------------------------*/
@@ -1228,11 +1317,13 @@ int iw_handler_set_thrspy(struct net_device *   dev,
                          union iwreq_data *    wrqu,
                          char *                extra)
 {
-#ifdef IW_WIRELESS_THRSPY
-       struct iw_spy_data *    spydata = (dev->priv +
-                                          dev->wireless_handlers->spy_offset);
+       struct iw_spy_data *    spydata = get_spydata(dev);
        struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
 
+       /* Make sure driver is not buggy or using the old API */
+       if(!spydata)
+               return -EOPNOTSUPP;
+
        /* Just do it */
        memcpy(&(spydata->spy_thr_low), &(threshold->low),
               2 * sizeof(struct iw_quality));
@@ -1245,9 +1336,6 @@ int iw_handler_set_thrspy(struct net_device *     dev,
 #endif /* WE_SPY_DEBUG */
 
        return 0;
-#else /* IW_WIRELESS_THRSPY */
-       return -EOPNOTSUPP;
-#endif /* IW_WIRELESS_THRSPY */
 }
 
 /*------------------------------------------------------------------*/
@@ -1259,22 +1347,20 @@ int iw_handler_get_thrspy(struct net_device *   dev,
                          union iwreq_data *    wrqu,
                          char *                extra)
 {
-#ifdef IW_WIRELESS_THRSPY
-       struct iw_spy_data *    spydata = (dev->priv +
-                                          dev->wireless_handlers->spy_offset);
+       struct iw_spy_data *    spydata = get_spydata(dev);
        struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
 
+       /* Make sure driver is not buggy or using the old API */
+       if(!spydata)
+               return -EOPNOTSUPP;
+
        /* Just do it */
        memcpy(&(threshold->low), &(spydata->spy_thr_low),
               2 * sizeof(struct iw_quality));
 
        return 0;
-#else /* IW_WIRELESS_THRSPY */
-       return -EOPNOTSUPP;
-#endif /* IW_WIRELESS_THRSPY */
 }
 
-#ifdef IW_WIRELESS_THRSPY
 /*------------------------------------------------------------------*/
 /*
  * Prepare and send a Spy Threshold event
@@ -1312,7 +1398,6 @@ static void iw_send_thrspy_event(struct net_device *      dev,
        /* Send event to user space */
        wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
 }
-#endif /* IW_WIRELESS_THRSPY */
 
 /* ---------------------------------------------------------------- */
 /*
@@ -1325,12 +1410,14 @@ void wireless_spy_update(struct net_device *    dev,
                         unsigned char *        address,
                         struct iw_quality *    wstats)
 {
-#ifdef IW_WIRELESS_SPY
-       struct iw_spy_data *    spydata = (dev->priv +
-                                          dev->wireless_handlers->spy_offset);
+       struct iw_spy_data *    spydata = get_spydata(dev);
        int                     i;
        int                     match = -1;
 
+       /* Make sure driver is not buggy or using the old API */
+       if(!spydata)
+               return;
+
 #ifdef WE_SPY_DEBUG
        printk(KERN_DEBUG "wireless_spy_update() :  offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
 #endif /* WE_SPY_DEBUG */
@@ -1342,7 +1429,7 @@ void wireless_spy_update(struct net_device *      dev,
                               sizeof(struct iw_quality));
                        match = i;
                }
-#ifdef IW_WIRELESS_THRSPY
+
        /* Generate an event if we cross the spy threshold.
         * To avoid event storms, we have a simple hysteresis : we generate
         * event only when we go under the low threshold or above the
@@ -1362,8 +1449,6 @@ void wireless_spy_update(struct net_device *      dev,
                        }
                }
        }
-#endif /* IW_WIRELESS_THRSPY */
-#endif /* IW_WIRELESS_SPY */
 }
 
 EXPORT_SYMBOL(iw_handler_get_spy);
index 74d6aac..2101da5 100644 (file)
@@ -1,17 +1,6 @@
 #
 # DECnet configuration
 #
-config DECNET_SIOCGIFCONF
-       bool "DECnet: SIOCGIFCONF support"
-       depends on DECNET
-       help
-         This option should only be turned on if you are really sure that
-         you know what you are doing. It can break other applications which
-         use this system call and the proper way to get the information
-         provided by this call is to use rtnetlink.
-
-         If unsure, say N.
-
 config DECNET_ROUTER
        bool "DECnet: router support (EXPERIMENTAL)"
        depends on DECNET && EXPERIMENTAL
index dc48de8..6128a02 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/config.h>
 #include <linux/net.h>
+#include <linux/module.h>
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
index 0b4ef49..42abbf3 100644 (file)
@@ -141,7 +141,7 @@ struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri)
  * whole size thats been asked for (plus 11 bytes of header). If this
  * fails, then we try for any size over 16 bytes for SOCK_STREAMS.
  */
-struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, int *err)
+struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, long timeo, int *err)
 {
        int space;
        int len;
@@ -151,7 +151,7 @@ struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, in
 
        while(skb == NULL) {
                if (signal_pending(current)) {
-                       *err = ERESTARTSYS;
+                       *err = sock_intr_errno(timeo);
                        break;
                }
 
index ee19a7e..e4b3af0 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/config.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
index 52969f3..95f4568 100644 (file)
@@ -453,7 +453,9 @@ int ip_vs_check_template(struct ip_vs_conn *ct)
         * Checking the dest server status.
         */
        if ((dest == NULL) ||
-           !(dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+           !(dest->flags & IP_VS_DEST_F_AVAILABLE) || 
+           (sysctl_ip_vs_expire_quiescent_template && 
+            (atomic_read(&dest->weight) == 0))) {
                IP_VS_DBG(9, "check_template: dest not available for "
                          "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
                          "-> d:%u.%u.%u.%u:%d\n",
@@ -580,7 +582,7 @@ ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
        cp->daddr          = daddr;
        cp->dport          = dport;
        cp->flags          = flags;
-       cp->lock           = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&cp->lock);
 
        /*
         * Set the entry is referenced by the current thread before hashing
@@ -894,7 +896,7 @@ int ip_vs_conn_init(void)
        }
 
        for (idx = 0; idx < CT_LOCKARRAY_SIZE; idx++)  {
-               __ip_vs_conntbl_lock_array[idx].l = RW_LOCK_UNLOCKED;
+               rwlock_init(&__ip_vs_conntbl_lock_array[idx].l);
        }
 
        proc_net_fops_create("ip_vs_conn", 0, &ip_vs_conn_fops);
index 0165cc6..a19a33c 100644 (file)
@@ -45,8 +45,7 @@
  * First port is set to the default port.
  */
 static int ports[IP_VS_APP_MAX_PORTS] = {21, 0};
-static int ports_c;
-module_param_array(ports, int, ports_c, 0);
+module_param_array(ports, int, NULL, 0);
 
 /*
  *     Debug level
index bce393e..c035838 100644 (file)
@@ -409,7 +409,7 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
        for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
                INIT_LIST_HEAD(&tbl->bucket[i]);
        }
-       tbl->lock = RW_LOCK_UNLOCKED;
+       rwlock_init(&tbl->lock);
        tbl->max_size = IP_VS_LBLC_TAB_SIZE*16;
        tbl->rover = 0;
        tbl->counter = 1;
index 1499c42..22b5dd5 100644 (file)
@@ -362,7 +362,7 @@ static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__u32 daddr)
        /* initilize its dest set */
        atomic_set(&(en->set.size), 0);
        en->set.list = NULL;
-       en->set.lock = RW_LOCK_UNLOCKED;
+       rwlock_init(&en->set.lock);
 
        return en;
 }
@@ -659,7 +659,7 @@ static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc)
        for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
                INIT_LIST_HEAD(&tbl->bucket[i]);
        }
-       tbl->lock = RW_LOCK_UNLOCKED;
+       rwlock_init(&tbl->lock);
        tbl->max_size = IP_VS_LBLCR_TAB_SIZE*16;
        tbl->rover = 0;
        tbl->counter = 1;
index d007bc9..ec79c08 100644 (file)
@@ -46,7 +46,7 @@ static DECLARE_LOCK(irc_buffer_lock);
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
 MODULE_LICENSE("GPL");
-module_param_array(ports, int, ports_c, 0400);
+module_param_array(ports, int, &ports_c, 0400);
 MODULE_PARM_DESC(ports, "port numbers of IRC servers");
 module_param(max_dcc_channels, int, 0400);
 MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
@@ -65,8 +65,8 @@ struct module *ip_conntrack_irc = THIS_MODULE;
 #define DEBUGP(format, args...)
 #endif
 
-int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port,
-             char **ad_beg_p, char **ad_end_p)
+static int parse_dcc(char *data, char *data_end, u_int32_t *ip,
+                    u_int16_t *port, char **ad_beg_p, char **ad_end_p)
 /* tries to get the ip_addr and port out of a dcc command
    return value: -1 on failure, 0 on success 
        data            pointer to first byte of DCC command data
index d132a3c..01a5e53 100644 (file)
@@ -28,7 +28,7 @@ MODULE_LICENSE("GPL");
 #define MAX_PORTS 8
 static int ports[MAX_PORTS];
 static int ports_c;
-module_param_array(ports, int, ports_c, 0400);
+module_param_array(ports, int, &ports_c, 0400);
 MODULE_PARM_DESC(ports, "port numbers of tftp servers");
 
 #if 0
index be00284..65da7b3 100644 (file)
@@ -34,7 +34,7 @@ MODULE_DESCRIPTION("ftp NAT helper");
 static int ports[MAX_PORTS];
 static int ports_c;
 
-module_param_array(ports, int, ports_c, 0400);
+module_param_array(ports, int, &ports_c, 0400);
 
 /* FIXME: Time out? --RR */
 
index 5eb60a2..4086f95 100644 (file)
@@ -42,7 +42,7 @@ static int ports_c;
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("IRC (DCC) NAT helper");
 MODULE_LICENSE("GPL");
-module_param_array(ports, int, ports_c, 0400);
+module_param_array(ports, int, &ports_c, 0400);
 MODULE_PARM_DESC(ports, "port numbers of IRC servers");
 
 /* FIXME: Time out? --RR */
index 6fb50de..7cbe088 100644 (file)
@@ -53,11 +53,13 @@ icmp_unique_tuple(struct ip_conntrack_tuple *tuple,
 
 static int
 icmp_manip_pkt(struct sk_buff **pskb,
-              unsigned int hdroff,
+              unsigned int iphdroff,
               const struct ip_conntrack_manip *manip,
               enum ip_nat_manip_type maniptype)
 {
+       struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
        struct icmphdr *hdr;
+       unsigned int hdroff = iphdroff + iph->ihl*4;
 
        if (!skb_ip_make_writable(pskb, hdroff + sizeof(*hdr)))
                return 0;
index 197bd01..281e19a 100644 (file)
@@ -84,11 +84,13 @@ tcp_unique_tuple(struct ip_conntrack_tuple *tuple,
 
 static int
 tcp_manip_pkt(struct sk_buff **pskb,
-             unsigned int hdroff,
+             unsigned int iphdroff,
              const struct ip_conntrack_manip *manip,
              enum ip_nat_manip_type maniptype)
 {
+       struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
        struct tcphdr *hdr;
+       unsigned int hdroff = iphdroff + iph->ihl*4;
        u_int32_t oldip;
        u_int16_t *portptr, oldport;
        int hdrsize = 8; /* TCP connection tracking guarantees this much */
@@ -106,11 +108,11 @@ tcp_manip_pkt(struct sk_buff **pskb,
 
        if (maniptype == IP_NAT_MANIP_SRC) {
                /* Get rid of src ip and src pt */
-               oldip = (*pskb)->nh.iph->saddr;
+               oldip = iph->saddr;
                portptr = &hdr->source;
        } else {
                /* Get rid of dst ip and dst pt */
-               oldip = (*pskb)->nh.iph->daddr;
+               oldip = iph->daddr;
                portptr = &hdr->dest;
        }
 
index 240004e..12c19bf 100644 (file)
@@ -83,11 +83,13 @@ udp_unique_tuple(struct ip_conntrack_tuple *tuple,
 
 static int
 udp_manip_pkt(struct sk_buff **pskb,
-             unsigned int hdroff,
+             unsigned int iphdroff,
              const struct ip_conntrack_manip *manip,
              enum ip_nat_manip_type maniptype)
 {
+       struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
        struct udphdr *hdr;
+       unsigned int hdroff = iphdroff + iph->ihl*4;
        u_int32_t oldip;
        u_int16_t *portptr;
 
@@ -97,11 +99,11 @@ udp_manip_pkt(struct sk_buff **pskb,
        hdr = (void *)(*pskb)->data + hdroff;
        if (maniptype == IP_NAT_MANIP_SRC) {
                /* Get rid of src ip and src pt */
-               oldip = (*pskb)->nh.iph->saddr;
+               oldip = iph->saddr;
                portptr = &hdr->source;
        } else {
                /* Get rid of dst ip and dst pt */
-               oldip = (*pskb)->nh.iph->daddr;
+               oldip = iph->daddr;
                portptr = &hdr->dest;
        }
        if (hdr->check) /* 0 is a special case meaning no checksum */
index b57103f..8f2e7dd 100644 (file)
@@ -39,7 +39,7 @@ static int unknown_unique_tuple(struct ip_conntrack_tuple *tuple,
 
 static int
 unknown_manip_pkt(struct sk_buff **pskb,
-                 unsigned int hdroff,
+                 unsigned int iphdroff,
                  const struct ip_conntrack_manip *manip,
                  enum ip_nat_manip_type maniptype)
 {
index 8ee96d1..9f727b6 100644 (file)
@@ -59,8 +59,8 @@ static struct
        struct ipt_replace repl;
        struct ipt_standard entries[3];
        struct ipt_error term;
-} nat_initial_table __initdata
-= { { "nat", NAT_VALID_HOOKS, 4,
+} nat_initial_table = {
+    { "nat", NAT_VALID_HOOKS, 4,
       sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
       { [NF_IP_PRE_ROUTING] = 0,
        [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
index cacaab6..aedd782 100644 (file)
@@ -42,7 +42,7 @@ MODULE_LICENSE("GPL");
 
 static int ports[MAX_PORTS];
 static int ports_c = 0;
-module_param_array(ports, int, ports_c, 0400);
+module_param_array(ports, int, &ports_c, 0400);
 MODULE_PARM_DESC(ports, "port numbers of tftp servers");
 
 #if 0
index 26dca38..d51e205 100644 (file)
@@ -162,6 +162,7 @@ static inline void
 __ipq_reset(void)
 {
        peer_pid = 0;
+       net_disable_timestamp();
        __ipq_set_mode(IPQ_COPY_NONE, 0);
        __ipq_flush(NF_DROP);
 }
@@ -257,7 +258,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
        }
        
        if (data_len)
-               memcpy(pmsg->payload, entry->skb->data, data_len);
+               if (skb_copy_bits(entry->skb, 0, pmsg->payload, data_len))
+                       BUG();
                
        nlh->nlmsg_len = skb->tail - old_tail;
        return skb;
@@ -362,6 +364,8 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
                }
                skb_put(e->skb, diff);
        }
+       if (!skb_ip_make_writable(&e->skb, v->data_len))
+               return -ENOMEM;
        memcpy(e->skb->data, v->payload, v->data_len);
        e->skb->nfcache |= NFC_ALTERED;
 
@@ -514,9 +518,10 @@ ipq_rcv_skb(struct sk_buff *skb)
                        write_unlock_bh(&queue_lock);
                        RCV_SKB_FAIL(-EBUSY);
                }
-       }
-       else
+       } else {
+               net_enable_timestamp();
                peer_pid = pid;
+       }
                
        write_unlock_bh(&queue_lock);
        
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);
index 120109c..f659ec3 100644 (file)
@@ -86,7 +86,7 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward)
                memcpy((*pskb)->data + (*pskb)->nh.iph->ihl*4,
                       &_tcph, sizeof(_tcph));
                if ((*pskb)->ip_summed == CHECKSUM_HW)
-                       if (skb_checksum_help(pskb, inward))
+                       if (skb_checksum_help(*pskb, inward))
                                return 0;
                (*pskb)->nfcache |= NFC_ALTERED;
        }
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);
index 15472b3..aa00874 100644 (file)
@@ -715,7 +715,7 @@ checkentry(const char *tablename,
        curr_table = vmalloc(sizeof(struct recent_ip_tables));
        if(curr_table == NULL) return -ENOMEM;
 
-       curr_table->list_lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&curr_table->list_lock);
        curr_table->next = NULL;
        curr_table->count = 1;
        curr_table->time_pos = 0;
index 5cda547..4dc9b16 100644 (file)
@@ -87,18 +87,6 @@ match(const struct sk_buff *skb,
                               info->invert, hotdrop);
 }
 
-static inline int find_syn_match(const struct ipt_entry_match *m)
-{
-       const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data;
-
-       if (strcmp(m->u.kernel.match->name, "tcp") == 0
-           && (tcpinfo->flg_cmp & TH_SYN)
-           && !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
-               return 1;
-
-       return 0;
-}
-
 static int
 checkentry(const char *tablename,
            const struct ipt_ip *ip,
index 6b291da..9af2aa7 100644 (file)
@@ -44,8 +44,8 @@ static struct
        struct ipt_replace repl;
        struct ipt_standard entries[3];
        struct ipt_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
+} initial_table = {
+    { "filter", FILTER_VALID_HOOKS, 4,
       sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
       { [NF_IP_LOCAL_IN] = 0,
        [NF_IP_FORWARD] = sizeof(struct ipt_standard),
index 3e23c6d..be78fa2 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/random.h>
 #include <linux/cache.h>
 #include <linux/init.h>
+#include <linux/time.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
 
 #include <linux/tcp_diag.h>
 
+struct tcpdiag_entry
+{
+       u32 *saddr;
+       u32 *daddr;
+       u16 sport;
+       u16 dport;
+       u16 family;
+       u16 userlocks;
+};
+
 static struct sock *tcpnl;
 
 
@@ -41,63 +52,8 @@ static struct sock *tcpnl;
    rta->rta_len = rtalen;                   \
    RTA_DATA(rta); })
 
-/* Return information about state of tcp endpoint in API format. */
-void tcp_get_info(struct sock *sk, struct tcp_info *info)
-{
-       struct tcp_opt *tp = tcp_sk(sk);
-       u32 now = tcp_time_stamp;
-
-       memset(info, 0, sizeof(*info));
-
-       info->tcpi_state = sk->sk_state;
-       info->tcpi_ca_state = tp->ca_state;
-       info->tcpi_retransmits = tp->retransmits;
-       info->tcpi_probes = tp->probes_out;
-       info->tcpi_backoff = tp->backoff;
-
-       if (tp->tstamp_ok)
-               info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
-       if (tp->sack_ok)
-               info->tcpi_options |= TCPI_OPT_SACK;
-       if (tp->wscale_ok) {
-               info->tcpi_options |= TCPI_OPT_WSCALE;
-               info->tcpi_snd_wscale = tp->snd_wscale;
-               info->tcpi_rcv_wscale = tp->rcv_wscale;
-       } 
-
-       if (tp->ecn_flags&TCP_ECN_OK)
-               info->tcpi_options |= TCPI_OPT_ECN;
-
-       info->tcpi_rto = jiffies_to_usecs(tp->rto);
-       info->tcpi_ato = jiffies_to_usecs(tp->ack.ato);
-       info->tcpi_snd_mss = tp->mss_cache_std;
-       info->tcpi_rcv_mss = tp->ack.rcv_mss;
-
-       info->tcpi_unacked = tcp_get_pcount(&tp->packets_out);
-       info->tcpi_sacked = tcp_get_pcount(&tp->sacked_out);
-       info->tcpi_lost = tcp_get_pcount(&tp->lost_out);
-       info->tcpi_retrans = tcp_get_pcount(&tp->retrans_out);
-       info->tcpi_fackets = tcp_get_pcount(&tp->fackets_out);
-
-       info->tcpi_last_data_sent = jiffies_to_msecs(now - tp->lsndtime);
-       info->tcpi_last_data_recv = jiffies_to_msecs(now - tp->ack.lrcvtime);
-       info->tcpi_last_ack_recv = jiffies_to_msecs(now - tp->rcv_tstamp);
-
-       info->tcpi_pmtu = tp->pmtu_cookie;
-       info->tcpi_rcv_ssthresh = tp->rcv_ssthresh;
-       info->tcpi_rtt = jiffies_to_usecs(tp->srtt)>>3;
-       info->tcpi_rttvar = jiffies_to_usecs(tp->mdev)>>2;
-       info->tcpi_snd_ssthresh = tp->snd_ssthresh;
-       info->tcpi_snd_cwnd = tp->snd_cwnd;
-       info->tcpi_advmss = tp->advmss;
-       info->tcpi_reordering = tp->reordering;
-
-       info->tcpi_rcv_rtt = jiffies_to_usecs(tp->rcv_rtt_est.rtt)>>3;
-       info->tcpi_rcv_space = tp->rcvq_space.space;
-}
-
 static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
-                       int ext, u32 pid, u32 seq)
+                       int ext, u32 pid, u32 seq, u16 nlmsg_flags)
 {
        struct inet_opt *inet = inet_sk(sk);
        struct tcp_opt *tp = tcp_sk(sk);
@@ -109,6 +65,7 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
        unsigned char    *b = skb->tail;
 
        nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
+       nlh->nlmsg_flags = nlmsg_flags;
        r = NLMSG_DATA(nlh);
        if (sk->sk_state != TCP_TIME_WAIT) {
                if (ext & (1<<(TCPDIAG_MEMINFO-1)))
@@ -146,7 +103,7 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
                r->tcpdiag_wqueue = 0;
                r->tcpdiag_uid = 0;
                r->tcpdiag_inode = 0;
-#ifdef CONFIG_IPV6
+#ifdef CONFIG_IP_TCPDIAG_IPV6
                if (r->tcpdiag_family == AF_INET6) {
                        ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src,
                                       &tw->tw_v6_rcv_saddr);
@@ -163,7 +120,7 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
        r->id.tcpdiag_src[0] = inet->rcv_saddr;
        r->id.tcpdiag_dst[0] = inet->daddr;
 
-#ifdef CONFIG_IPV6
+#ifdef CONFIG_IP_TCPDIAG_IPV6
        if (r->tcpdiag_family == AF_INET6) {
                struct ipv6_pinfo *np = inet6_sk(sk);
 
@@ -231,11 +188,19 @@ nlmsg_failure:
        return -1;
 }
 
-extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
-#ifdef CONFIG_IPV6
+extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport,
+                                 int dif);
+#ifdef CONFIG_IP_TCPDIAG_IPV6
 extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
                                  struct in6_addr *daddr, u16 dport,
                                  int dif);
+#else
+static inline struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
+                                        struct in6_addr *daddr, u16 dport,
+                                        int dif)
+{
+       return NULL;
+}
 #endif
 
 static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
@@ -250,7 +215,7 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
                                   req->id.tcpdiag_src[0], req->id.tcpdiag_sport,
                                   req->id.tcpdiag_if);
        }
-#ifdef CONFIG_IPV6
+#ifdef CONFIG_IP_TCPDIAG_IPV6
        else if (req->tcpdiag_family == AF_INET6) {
                sk = tcp_v6_lookup((struct in6_addr*)req->id.tcpdiag_dst, req->id.tcpdiag_dport,
                                   (struct in6_addr*)req->id.tcpdiag_src, req->id.tcpdiag_sport,
@@ -280,7 +245,7 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
 
        if (tcpdiag_fill(rep, sk, req->tcpdiag_ext,
                         NETLINK_CB(in_skb).pid,
-                        nlh->nlmsg_seq) <= 0)
+                        nlh->nlmsg_seq, 0) <= 0)
                BUG();
 
        err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
@@ -324,11 +289,11 @@ static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
 }
 
 
-static int tcpdiag_bc_run(const void *bc, int len, struct sock *sk)
+static int tcpdiag_bc_run(const void *bc, int len,
+                         const struct tcpdiag_entry *entry)
 {
        while (len > 0) {
                int yes = 1;
-               struct inet_opt *inet = inet_sk(sk);
                const struct tcpdiag_bc_op *op = bc;
 
                switch (op->code) {
@@ -338,19 +303,19 @@ static int tcpdiag_bc_run(const void *bc, int len, struct sock *sk)
                        yes = 0;
                        break;
                case TCPDIAG_BC_S_GE:
-                       yes = inet->num >= op[1].no;
+                       yes = entry->sport >= op[1].no;
                        break;
                case TCPDIAG_BC_S_LE:
-                       yes = inet->num <= op[1].no;
+                       yes = entry->dport <= op[1].no;
                        break;
                case TCPDIAG_BC_D_GE:
-                       yes = ntohs(inet->dport) >= op[1].no;
+                       yes = entry->dport >= op[1].no;
                        break;
                case TCPDIAG_BC_D_LE:
-                       yes = ntohs(inet->dport) <= op[1].no;
+                       yes = entry->dport <= op[1].no;
                        break;
                case TCPDIAG_BC_AUTO:
-                       yes = !(sk->sk_userlocks & SOCK_BINDPORT_LOCK);
+                       yes = !(entry->userlocks & SOCK_BINDPORT_LOCK);
                        break;
                case TCPDIAG_BC_S_COND:
                case TCPDIAG_BC_D_COND:
@@ -360,7 +325,7 @@ static int tcpdiag_bc_run(const void *bc, int len, struct sock *sk)
 
                        if (cond->port != -1 &&
                            cond->port != (op->code == TCPDIAG_BC_S_COND ?
-                                            inet->num : ntohs(inet->dport))) {
+                                            entry->sport : entry->dport)) {
                                yes = 0;
                                break;
                        }
@@ -368,26 +333,14 @@ static int tcpdiag_bc_run(const void *bc, int len, struct sock *sk)
                        if (cond->prefix_len == 0)
                                break;
 
-#ifdef CONFIG_IPV6
-                       if (sk->sk_family == AF_INET6) {
-                               struct ipv6_pinfo *np = inet6_sk(sk);
-
-                               if (op->code == TCPDIAG_BC_S_COND)
-                                       addr = (u32*)&np->rcv_saddr;
-                               else
-                                       addr = (u32*)&np->daddr;
-                       } else
-#endif
-                       {
-                               if (op->code == TCPDIAG_BC_S_COND)
-                                       addr = &inet->rcv_saddr;
-                               else
-                                       addr = &inet->daddr;
-                       }
+                       if (op->code == TCPDIAG_BC_S_COND)
+                               addr = entry->saddr;
+                       else
+                               addr = entry->daddr;
 
                        if (bitstring_match(addr, cond->addr, cond->prefix_len))
                                break;
-                       if (sk->sk_family == AF_INET6 &&
+                       if (entry->family == AF_INET6 &&
                            cond->family == AF_INET) {
                                if (addr[0] == 0 && addr[1] == 0 &&
                                    addr[2] == htonl(0xffff) &&
@@ -466,16 +419,182 @@ static int tcpdiag_bc_audit(const void *bytecode, int bytecode_len)
        return len == 0 ? 0 : -EINVAL;
 }
 
+static int tcpdiag_dump_sock(struct sk_buff *skb, struct sock *sk,
+                            struct netlink_callback *cb)
+{
+       struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
+
+       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+               struct tcpdiag_entry entry;
+               struct rtattr *bc = (struct rtattr *)(r + 1);
+               struct inet_opt *inet = inet_sk(sk);
+
+               entry.family = sk->sk_family;
+#ifdef CONFIG_IP_TCPDIAG_IPV6
+               if (entry.family == AF_INET6) {
+                       struct ipv6_pinfo *np = inet6_sk(sk);
+
+                       entry.saddr = np->rcv_saddr.s6_addr32;
+                       entry.daddr = np->daddr.s6_addr32;
+               } else
+#endif
+               {
+                       entry.saddr = &inet->rcv_saddr;
+                       entry.daddr = &inet->daddr;
+               }
+               entry.sport = inet->num;
+               entry.dport = ntohs(inet->dport);
+               entry.userlocks = sk->sk_userlocks;
+
+               if (!tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+                       return 0;
+       }
+
+       return tcpdiag_fill(skb, sk, r->tcpdiag_ext, NETLINK_CB(cb->skb).pid,
+                           cb->nlh->nlmsg_seq, NLM_F_MULTI);
+}
+
+static int tcpdiag_fill_req(struct sk_buff *skb, struct sock *sk,
+                           struct open_request *req,
+                           u32 pid, u32 seq)
+{
+       struct inet_opt *inet = inet_sk(sk);
+       unsigned char *b = skb->tail;
+       struct tcpdiagmsg *r;
+       struct nlmsghdr *nlh;
+       long tmo;
+
+       nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
+       nlh->nlmsg_flags = NLM_F_MULTI;
+       r = NLMSG_DATA(nlh);
+
+       r->tcpdiag_family = sk->sk_family;
+       r->tcpdiag_state = TCP_SYN_RECV;
+       r->tcpdiag_timer = 1;
+       r->tcpdiag_retrans = req->retrans;
+
+       r->id.tcpdiag_if = sk->sk_bound_dev_if;
+       r->id.tcpdiag_cookie[0] = (u32)(unsigned long)req;
+       r->id.tcpdiag_cookie[1] = (u32)(((unsigned long)req >> 31) >> 1);
+
+       tmo = req->expires - jiffies;
+       if (tmo < 0)
+               tmo = 0;
+
+       r->id.tcpdiag_sport = inet->sport;
+       r->id.tcpdiag_dport = req->rmt_port;
+       r->id.tcpdiag_src[0] = req->af.v4_req.loc_addr;
+       r->id.tcpdiag_dst[0] = req->af.v4_req.rmt_addr;
+       r->tcpdiag_expires = jiffies_to_msecs(tmo),
+       r->tcpdiag_rqueue = 0;
+       r->tcpdiag_wqueue = 0;
+       r->tcpdiag_uid = sock_i_uid(sk);
+       r->tcpdiag_inode = 0;
+#ifdef CONFIG_IP_TCPDIAG_IPV6
+       if (r->tcpdiag_family == AF_INET6) {
+               ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src,
+                              &req->af.v6_req.loc_addr);
+               ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_dst,
+                              &req->af.v6_req.rmt_addr);
+       }
+#endif
+       nlh->nlmsg_len = skb->tail - b;
+
+       return skb->len;
+
+nlmsg_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+static int tcpdiag_dump_reqs(struct sk_buff *skb, struct sock *sk,
+                            struct netlink_callback *cb)
+{
+       struct tcpdiag_entry entry;
+       struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
+       struct tcp_opt *tp = tcp_sk(sk);
+       struct tcp_listen_opt *lopt;
+       struct rtattr *bc = NULL;
+       struct inet_opt *inet = inet_sk(sk);
+       int j, s_j;
+       int reqnum, s_reqnum;
+       int err = 0;
+
+       s_j = cb->args[3];
+       s_reqnum = cb->args[4];
+
+       if (s_j > 0)
+               s_j--;
+
+       entry.family = sk->sk_family;
+
+       read_lock_bh(&tp->syn_wait_lock);
+
+       lopt = tp->listen_opt;
+       if (!lopt || !lopt->qlen)
+               goto out;
+
+       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+               bc = (struct rtattr *)(r + 1);
+               entry.sport = inet->num;
+               entry.userlocks = sk->sk_userlocks;
+       }
+
+       for (j = s_j; j < TCP_SYNQ_HSIZE; j++) {
+               struct open_request *req, *head = lopt->syn_table[j];
+
+               reqnum = 0;
+               for (req = head; req; reqnum++, req = req->dl_next) {
+                       if (reqnum < s_reqnum)
+                               continue;
+                       if (r->id.tcpdiag_dport != req->rmt_port &&
+                           r->id.tcpdiag_dport)
+                               continue;
+
+                       if (bc) {
+                               entry.saddr =
+#ifdef CONFIG_IP_TCPDIAG_IPV6
+                                       (entry.family == AF_INET6) ?
+                                       req->af.v6_req.loc_addr.s6_addr32 :
+#endif
+                                       &req->af.v4_req.loc_addr;
+                               entry.daddr = 
+#ifdef CONFIG_IP_TCPDIAG_IPV6
+                                       (entry.family == AF_INET6) ?
+                                       req->af.v6_req.rmt_addr.s6_addr32 :
+#endif
+                                       &req->af.v4_req.rmt_addr;
+                               entry.dport = ntohs(req->rmt_port);
+
+                               if (!tcpdiag_bc_run(RTA_DATA(bc),
+                                                   RTA_PAYLOAD(bc), &entry))
+                                       continue;
+                       }
+
+                       err = tcpdiag_fill_req(skb, sk, req,
+                                              NETLINK_CB(cb->skb).pid,
+                                              cb->nlh->nlmsg_seq);
+                       if (err < 0) {
+                               cb->args[3] = j + 1;
+                               cb->args[4] = reqnum;
+                               goto out;
+                       }
+               }
+
+               s_reqnum = 0;
+       }
+
+out:
+       read_unlock_bh(&tp->syn_wait_lock);
+
+       return err;
+}
 
 static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
        int i, num;
        int s_i, s_num;
        struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
-       struct rtattr *bc = NULL;
-
-       if (cb->nlh->nlmsg_len > 4+NLMSG_SPACE(sizeof(struct tcpdiagreq)))
-               bc = (struct rtattr*)(r+1);
 
        s_i = cb->args[1];
        s_num = num = cb->args[2];
@@ -488,31 +607,47 @@ static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        struct sock *sk;
                        struct hlist_node *node;
 
-                       if (i > s_i)
-                               s_num = 0;
-
                        num = 0;
                        sk_for_each(sk, node, &tcp_listening_hash[i]) {
                                struct inet_opt *inet = inet_sk(sk);
-                               if (num < s_num)
-                                       goto next_listen;
-                               if (!(r->tcpdiag_states&TCPF_LISTEN) ||
-                                   r->id.tcpdiag_dport)
-                                       goto next_listen;
+
+                               if (num < s_num) {
+                                       num++;
+                                       continue;
+                               }
+
                                if (r->id.tcpdiag_sport != inet->sport &&
                                    r->id.tcpdiag_sport)
                                        goto next_listen;
-                               if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
+
+                               if (!(r->tcpdiag_states&TCPF_LISTEN) ||
+                                   r->id.tcpdiag_dport ||
+                                   cb->args[3] > 0)
+                                       goto syn_recv;
+
+                               if (tcpdiag_dump_sock(skb, sk, cb) < 0) {
+                                       tcp_listen_unlock();
+                                       goto done;
+                               }
+
+syn_recv:
+                               if (!(r->tcpdiag_states&TCPF_SYN_RECV))
                                        goto next_listen;
-                               if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
-                                                NETLINK_CB(cb->skb).pid,
-                                                cb->nlh->nlmsg_seq) <= 0) {
+
+                               if (tcpdiag_dump_reqs(skb, sk, cb) < 0) {
                                        tcp_listen_unlock();
                                        goto done;
                                }
+
 next_listen:
+                               cb->args[3] = 0;
+                               cb->args[4] = 0;
                                ++num;
                        }
+
+                       s_num = 0;
+                       cb->args[3] = 0;
+                       cb->args[4] = 0;
                }
                tcp_listen_unlock();
 skip_listen_ht:
@@ -546,11 +681,7 @@ skip_listen_ht:
                                goto next_normal;
                        if (r->id.tcpdiag_dport != inet->dport && r->id.tcpdiag_dport)
                                goto next_normal;
-                       if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
-                               goto next_normal;
-                       if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
-                                        NETLINK_CB(cb->skb).pid,
-                                        cb->nlh->nlmsg_seq) <= 0) {
+                       if (tcpdiag_dump_sock(skb, sk, cb) < 0) {
                                read_unlock_bh(&head->lock);
                                goto done;
                        }
@@ -571,11 +702,7 @@ next_normal:
                                if (r->id.tcpdiag_dport != inet->dport &&
                                    r->id.tcpdiag_dport)
                                        goto next_dying;
-                               if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
-                                       goto next_dying;
-                               if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
-                                                NETLINK_CB(cb->skb).pid,
-                                                cb->nlh->nlmsg_seq) <= 0) {
+                               if (tcpdiag_dump_sock(skb, sk, cb) < 0) {
                                        read_unlock_bh(&head->lock);
                                        goto done;
                                }
@@ -657,9 +784,19 @@ static void tcpdiag_rcv(struct sock *sk, int len)
        }
 }
 
-void __init tcpdiag_init(void)
+static int __init tcpdiag_init(void)
 {
        tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv);
        if (tcpnl == NULL)
-               panic("tcpdiag_init: Cannot create netlink socket.");
+               return -ENOMEM;
+       return 0;
 }
+
+static void __exit tcpdiag_exit(void)
+{
+       sock_release(tcpnl->sk_socket);
+}
+
+module_init(tcpdiag_init);
+module_exit(tcpdiag_exit);
+MODULE_LICENSE("GPL");
index 47e54d4..2d3849c 100644 (file)
@@ -9,6 +9,7 @@
  *     
  */
 
+#include <linux/module.h>
 #include <linux/string.h>
 #include <net/inet_ecn.h>
 #include <net/ip.h>
@@ -19,6 +20,8 @@ int xfrm4_rcv(struct sk_buff *skb)
        return xfrm4_rcv_encap(skb, 0);
 }
 
+EXPORT_SYMBOL(xfrm4_rcv);
+
 static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
 {
        struct iphdr *outer_iph = skb->nh.iph;
index 21832df..3c70b08 100644 (file)
@@ -91,16 +91,14 @@ out:
        return ret;
 }
 
-int xfrm4_output(struct sk_buff **pskb)
+int xfrm4_output(struct sk_buff *skb)
 {
-       struct sk_buff *skb = *pskb;
        struct dst_entry *dst = skb->dst;
        struct xfrm_state *x = dst->xfrm;
        int err;
        
        if (skb->ip_summed == CHECKSUM_HW) {
-               err = skb_checksum_help(pskb, 0);
-               skb = *pskb;
+               err = skb_checksum_help(skb, 0);
                if (err)
                        goto error_nolock;
        }
index fd87a5a..e66ca93 100644 (file)
@@ -52,8 +52,8 @@ config INET6_IPCOMP
        select CRYPTO
        select CRYPTO_DEFLATE
        ---help---
-         Support for IP Paylod Compression (RFC3173), typically needed
-         for IPsec.
+         Support for IP Payload Compression Protocol (IPComp) (RFC3173),
+         typically needed for IPsec.
 
          If unsure, say Y.
 
index 1816b81..798d78c 100644 (file)
@@ -433,7 +433,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
 
        if (fn->fn_flags&RTN_TL_ROOT &&
            fn->leaf == &ip6_null_entry &&
-           !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF | RTF_ALLONLINK)) ){
+           !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ){
                fn->leaf = rt;
                rt->u.next = NULL;
                goto out;
@@ -451,8 +451,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
 
                        if (iter->rt6i_dev == rt->rt6i_dev &&
                            iter->rt6i_idev == rt->rt6i_idev &&
-                           ipv6_addr_cmp(&iter->rt6i_gateway,
-                                          &rt->rt6i_gateway) == 0) {
+                           ipv6_addr_equal(&iter->rt6i_gateway,
+                                           &rt->rt6i_gateway)) {
                                if (!(iter->rt6i_flags&RTF_EXPIRES))
                                        return -EEXIST;
                                iter->rt6i_expires = rt->rt6i_expires;
index 75f9ac7..bcf6502 100644 (file)
@@ -167,6 +167,7 @@ static inline void
 __ipq_reset(void)
 {
        peer_pid = 0;
+       net_disable_timestamp();
        __ipq_set_mode(IPQ_COPY_NONE, 0);
        __ipq_flush(NF_DROP);
 }
@@ -262,7 +263,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
        }
        
        if (data_len)
-               memcpy(pmsg->payload, entry->skb->data, data_len);
+               if (skb_copy_bits(entry->skb, 0, pmsg->payload, data_len))
+                       BUG();
                
        nlh->nlmsg_len = skb->tail - old_tail;
        return skb;
@@ -366,6 +368,8 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
                }
                skb_put(e->skb, diff);
        }
+       if (!skb_ip_make_writable(&e->skb, v->data_len))
+               return -ENOMEM;
        memcpy(e->skb->data, v->payload, v->data_len);
        e->skb->nfcache |= NFC_ALTERED;
 
@@ -376,8 +380,8 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
         */
        if (e->info->hook == NF_IP_LOCAL_OUT) {
                struct ipv6hdr *iph = e->skb->nh.ipv6h;
-               if (ipv6_addr_cmp(&iph->daddr, &e->rt_info.daddr) ||
-                   ipv6_addr_cmp(&iph->saddr, &e->rt_info.saddr))
+               if (!ipv6_addr_equal(&iph->daddr, &e->rt_info.daddr) ||
+                   !ipv6_addr_equal(&iph->saddr, &e->rt_info.saddr))
                        return ip6_route_me_harder(e->skb);
        }
        return 0;
@@ -517,9 +521,10 @@ ipq_rcv_skb(struct sk_buff *skb)
                        write_unlock_bh(&queue_lock);
                        RCV_SKB_FAIL(-EBUSY);
                }
-       }
-       else
+       } else {
+               net_enable_timestamp();
                peer_pid = pid;
+       }
                
        write_unlock_bh(&queue_lock);
        
index ce287d2..d09ceb0 100644 (file)
@@ -20,9 +20,9 @@ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
 
 static unsigned int
 target(struct sk_buff **pskb,
-       unsigned int hooknum,
        const struct net_device *in,
        const struct net_device *out,
+       unsigned int hooknum,
        const void *targinfo,
        void *userinfo)
 {
index f5b9efd..d5b94f1 100644 (file)
@@ -31,12 +31,12 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
 static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
 {
-       int r=0;
-       DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
-              min,spi,max);
-       r=(spi >= min && spi <= max) ^ invert;
-       DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
-       return r;
+       int r=0;
+       DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+              min,spi,max);
+       r = (spi >= min && spi <= max) ^ invert;
+       DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
+       return r;
 }
 
 static int
@@ -45,125 +45,124 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *protohdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
-       struct ip_auth_hdr *ah = NULL;
-       const struct ip6t_ah *ahinfo = matchinfo;
-       unsigned int temp;
-       int len;
-       u8 nexthdr;
-       unsigned int ptr;
-       unsigned int hdrlen = 0;
-
-       /*DEBUGP("IPv6 AH entered\n");*/
-       /* if (opt->auth == 0) return 0;
-       * It does not filled on output */
-
-       /* type of the 1st exthdr */
-       nexthdr = skb->nh.ipv6h->nexthdr;
-       /* pointer to the 1st exthdr */
-       ptr = sizeof(struct ipv6hdr);
-       /* available length */
-       len = skb->len - ptr;
-       temp = 0;
-
-        while (ip6t_ext_hdr(nexthdr)) {
-               struct ipv6_opt_hdr *hdr;
-
-              DEBUGP("ipv6_ah header iteration \n");
-
-              /* Is there enough space for the next ext header? */
-                if (len < (int)sizeof(struct ipv6_opt_hdr))
-                        return 0;
-              /* No more exthdr -> evaluate */
-                if (nexthdr == NEXTHDR_NONE) {
-                     break;
-              }
-              /* ESP -> evaluate */
-                if (nexthdr == NEXTHDR_ESP) {
-                     break;
-              }
-
-              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
-
-              /* Calculate the header length */
-                if (nexthdr == NEXTHDR_FRAGMENT) {
-                        hdrlen = 8;
-                } else if (nexthdr == NEXTHDR_AUTH)
-                        hdrlen = (hdr->hdrlen+2)<<2;
-                else
-                        hdrlen = ipv6_optlen(hdr);
-
-              /* AH -> evaluate */
-                if (nexthdr == NEXTHDR_AUTH) {
-                     temp |= MASK_AH;
-                     break;
-              }
-
-
-              /* set the flag */
-              switch (nexthdr){
-                     case NEXTHDR_HOP:
-                     case NEXTHDR_ROUTING:
-                     case NEXTHDR_FRAGMENT:
-                     case NEXTHDR_AUTH:
-                     case NEXTHDR_DEST:
-                            break;
-                     default:
-                            DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr);
-                            return 0;
-                            break;
-              }
-
-                nexthdr = hdr->nexthdr;
-                len -= hdrlen;
-                ptr += hdrlen;
-               if ( ptr > skb->len ) {
+       struct ip_auth_hdr *ah = NULL, _ah;
+       const struct ip6t_ah *ahinfo = matchinfo;
+       unsigned int temp;
+       int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+
+       /*DEBUGP("IPv6 AH entered\n");*/
+       /* if (opt->auth == 0) return 0;
+       * It does not filled on output */
+
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+       while (ip6t_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr _hdr, *hp;
+
+               DEBUGP("ipv6_ah header iteration \n");
+
+               /* Is there enough space for the next ext header? */
+               if (len < sizeof(struct ipv6_opt_hdr))
+                       return 0;
+               /* No more exthdr -> evaluate */
+               if (nexthdr == NEXTHDR_NONE)
+                       break;
+               /* ESP -> evaluate */
+               if (nexthdr == NEXTHDR_ESP)
+                       break;
+
+               hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
+               BUG_ON(hp == NULL);
+
+               /* Calculate the header length */
+               if (nexthdr == NEXTHDR_FRAGMENT)
+                       hdrlen = 8;
+               else if (nexthdr == NEXTHDR_AUTH)
+                       hdrlen = (hp->hdrlen+2)<<2;
+               else
+                       hdrlen = ipv6_optlen(hp);
+
+               /* AH -> evaluate */
+               if (nexthdr == NEXTHDR_AUTH) {
+                       temp |= MASK_AH;
+                       break;
+               }
+
+               
+               /* set the flag */
+               switch (nexthdr) {
+               case NEXTHDR_HOP:
+               case NEXTHDR_ROUTING:
+               case NEXTHDR_FRAGMENT:
+               case NEXTHDR_AUTH:
+               case NEXTHDR_DEST:
+                       break;
+               default:
+                       DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr);
+                       return 0;
+               }
+
+               nexthdr = hp->nexthdr;
+               len -= hdrlen;
+               ptr += hdrlen;
+               if (ptr > skb->len) {
                        DEBUGP("ipv6_ah: new pointer too large! \n");
                        break;
                }
-        }
-
-       /* AH header not found */
-       if ( temp != MASK_AH ) return 0;
-
-       if (len < (int)sizeof(struct ip_auth_hdr)){
-              *hotdrop = 1;
-                       return 0;
-       }
-
-       ah = (struct ip_auth_hdr *) (skb->data + ptr);
-
-       DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
-       DEBUGP("RES %04X ", ah->reserved);
-       DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
-
-       DEBUGP("IPv6 AH spi %02X ",
-                       (spi_match(ahinfo->spis[0], ahinfo->spis[1],
-                           ntohl(ah->spi),
-                           !!(ahinfo->invflags & IP6T_AH_INV_SPI))));
-       DEBUGP("len %02X %04X %02X ",
-                       ahinfo->hdrlen, hdrlen,
-                       (!ahinfo->hdrlen ||
-                           (ahinfo->hdrlen == hdrlen) ^
-                           !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
-       DEBUGP("res %02X %04X %02X\n", 
-                       ahinfo->hdrres, ah->reserved,
-                       !(ahinfo->hdrres && ah->reserved));
-
-       return (ah != NULL)
-              &&
-              (spi_match(ahinfo->spis[0], ahinfo->spis[1],
-                           ntohl(ah->spi),
-                           !!(ahinfo->invflags & IP6T_AH_INV_SPI)))
-              &&
-              (!ahinfo->hdrlen ||
-                           (ahinfo->hdrlen == hdrlen) ^
-                           !!(ahinfo->invflags & IP6T_AH_INV_LEN))
-              &&
-              !(ahinfo->hdrres && ah->reserved);
+       }
+
+       /* AH header not found */
+       if (temp != MASK_AH)
+               return 0;
+
+       if (len < sizeof(struct ip_auth_hdr)){
+               *hotdrop = 1;
+               return 0;
+       }
+
+       ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
+       BUG_ON(ah == NULL);
+
+       DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
+       DEBUGP("RES %04X ", ah->reserved);
+       DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
+
+       DEBUGP("IPv6 AH spi %02X ",
+              (spi_match(ahinfo->spis[0], ahinfo->spis[1],
+                         ntohl(ah->spi),
+                         !!(ahinfo->invflags & IP6T_AH_INV_SPI))));
+       DEBUGP("len %02X %04X %02X ",
+              ahinfo->hdrlen, hdrlen,
+              (!ahinfo->hdrlen ||
+               (ahinfo->hdrlen == hdrlen) ^
+               !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
+       DEBUGP("res %02X %04X %02X\n",
+              ahinfo->hdrres, ah->reserved,
+              !(ahinfo->hdrres && ah->reserved));
+
+       return (ah != NULL)
+              &&
+              (spi_match(ahinfo->spis[0], ahinfo->spis[1],
+                         ntohl(ah->spi),
+                         !!(ahinfo->invflags & IP6T_AH_INV_SPI)))
+              &&
+              (!ahinfo->hdrlen ||
+               (ahinfo->hdrlen == hdrlen) ^
+               !!(ahinfo->invflags & IP6T_AH_INV_LEN))
+              &&
+              !(ahinfo->hdrres && ah->reserved);
 }
 
 /* Called when user tries to insert an entry of this type. */
@@ -174,20 +173,18 @@ checkentry(const char *tablename,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
-       const struct ip6t_ah *ahinfo = matchinfo;
-
-       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
-              DEBUGP("ip6t_ah: matchsize %u != %u\n",
-                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
-              return 0;
-       }
-       if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
-              DEBUGP("ip6t_ah: unknown flags %X\n",
-                      ahinfo->invflags);
-              return 0;
-       }
-
-       return 1;
+       const struct ip6t_ah *ahinfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
+               DEBUGP("ip6t_ah: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
+               return 0;
+       }
+       if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
+               DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
+               return 0;
+       }
+       return 1;
 }
 
 static struct ip6t_match ah_match = {
@@ -199,12 +196,12 @@ static struct ip6t_match ah_match = {
 
 static int __init init(void)
 {
-       return ip6t_register_match(&ah_match);
+       return ip6t_register_match(&ah_match);
 }
 
 static void __exit cleanup(void)
 {
-       ip6t_unregister_match(&ah_match);
+       ip6t_unregister_match(&ah_match);
 }
 
 module_init(init);
index 2d38503..540925e 100644 (file)
@@ -7,7 +7,6 @@
  * published by the Free Software Foundation.
  */
 
-
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ipv6.h>
@@ -20,8 +19,6 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_opts.h>
 
-#define LOW(n)         (n & 0x00FF)
-
 #define HOPBYHOP       0
 
 MODULE_LICENSE("GPL");
@@ -48,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
  *     0       -> invariant
  *     1       -> can change the routing
  *  (Type & 0x1F) Type
- *      0      -> PAD0 (only 1 byte!)
- *      1      -> PAD1 LENGTH info (total length = length + 2)
+ *      0      -> Pad1 (only 1 byte!)
+ *      1      -> PadN LENGTH info (total length = length + 2)
  *      C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
  *      5      -> RTALERT 2 x x
  */
@@ -60,11 +57,10 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *protohdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
-       struct ipv6_opt_hdr *optsh = NULL;
+       struct ipv6_opt_hdr _optsh, *oh;
        const struct ip6t_opts *optinfo = matchinfo;
        unsigned int temp;
        unsigned int len;
@@ -72,7 +68,9 @@ match(const struct sk_buff *skb,
        unsigned int ptr;
        unsigned int hdrlen = 0;
        unsigned int ret = 0;
-       u_int16_t *optdesc = NULL;
+       u8 _opttype, *tp = NULL;
+       u8 _optlen, *lp = NULL;
+       unsigned int optlen;
        
        /* type of the 1st exthdr */
        nexthdr = skb->nh.ipv6h->nexthdr;
@@ -83,7 +81,7 @@ match(const struct sk_buff *skb,
        temp = 0;
 
         while (ip6t_ext_hdr(nexthdr)) {
-               struct ipv6_opt_hdr *hdr;
+               struct ipv6_opt_hdr _hdr, *hp;
 
               DEBUGP("ipv6_opts header iteration \n");
 
@@ -99,15 +97,16 @@ match(const struct sk_buff *skb,
                      break;
               }
 
-              hdr=(void *)(skb->data)+ptr;
+             hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
+             BUG_ON(hp == NULL);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
                         hdrlen = 8;
                 } else if (nexthdr == NEXTHDR_AUTH)
-                        hdrlen = (hdr->hdrlen+2)<<2;
+                        hdrlen = (hp->hdrlen+2)<<2;
                 else
-                        hdrlen = ipv6_optlen(hdr);
+                        hdrlen = ipv6_optlen(hp);
 
               /* OPTS -> evaluate */
 #if HOPBYHOP
@@ -135,7 +134,7 @@ match(const struct sk_buff *skb,
                             break;
               }
 
-                nexthdr = hdr->nexthdr;
+                nexthdr = hp->nexthdr;
                 len -= hdrlen;
                 ptr += hdrlen;
                if ( ptr > skb->len ) {
@@ -161,9 +160,10 @@ match(const struct sk_buff *skb,
                        return 0;
        }
 
-       optsh=(void *)(skb->data)+ptr;
+       oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
+       BUG_ON(oh == NULL);
 
-       DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
+       DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
 
        DEBUGP("len %02X %04X %02X ",
                        optinfo->hdrlen, hdrlen,
@@ -171,13 +171,12 @@ match(const struct sk_buff *skb,
                            ((optinfo->hdrlen == hdrlen) ^
                            !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
 
-       ret = (optsh != NULL)
+       ret = (oh != NULL)
                        &&
                (!(optinfo->flags & IP6T_OPTS_LEN) ||
                            ((optinfo->hdrlen == hdrlen) ^
                            !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
 
-       temp = len = 0;
        ptr += 2;
        hdrlen -= 2;
        if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
@@ -188,48 +187,59 @@ match(const struct sk_buff *skb,
                DEBUGP("Strict ");
                DEBUGP("#%d ",optinfo->optsnr);
                for(temp=0; temp<optinfo->optsnr; temp++){
-                       optdesc = (void *)(skb->data)+ptr;
+                       /* type field exists ? */
+                       if (hdrlen < 1)
+                               break;
+                       tp = skb_header_pointer(skb, ptr, sizeof(_opttype),
+                                               &_opttype);
+                       if (tp == NULL)
+                               break;
+
                        /* Type check */
-                       if ( (unsigned char)*optdesc != 
-                               (optinfo->opts[temp] & 0xFF00)>>8 ){
+                       if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){
                                DEBUGP("Tbad %02X %02X\n",
-                                               (unsigned char)*optdesc,
-                                               (optinfo->opts[temp] &
-                                                0xFF00)>>8);
+                                      *tp,
+                                      (optinfo->opts[temp] & 0xFF00)>>8);
                                return 0;
                        } else {
                                DEBUGP("Tok ");
                        }
                        /* Length check */
-                       if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
-                               (unsigned char)*optdesc != 0){
-                               if ( ntohs((u16)*optdesc) != 
-                                               optinfo->opts[temp] ){
-                                       DEBUGP("Lbad %02X %04X %04X\n",
-                                                       (unsigned char)*optdesc,
-                                                       ntohs((u16)*optdesc),
-                                                       optinfo->opts[temp]);
+                       if (*tp) {
+                               u16 spec_len;
+
+                               /* length field exists ? */
+                               if (hdrlen < 2)
+                                       break;
+                               lp = skb_header_pointer(skb, ptr + 1,
+                                                       sizeof(_optlen),
+                                                       &_optlen);
+                               if (lp == NULL)
+                                       break;
+                               spec_len = optinfo->opts[temp] & 0x00FF;
+
+                               if (spec_len != 0x00FF && spec_len != *lp) {
+                                       DEBUGP("Lbad %02X %04X\n", *lp,
+                                              spec_len);
                                        return 0;
-                               } else {
-                                       DEBUGP("Lok ");
                                }
-                       }
-                       /* Step to the next */
-                       if ((unsigned char)*optdesc == 0){
-                               DEBUGP("PAD0 \n");
-                               ptr++;
-                               hdrlen--;
+                               DEBUGP("Lok ");
+                               optlen = *lp + 2;
                        } else {
-                               ptr += LOW(ntohs(*optdesc));
-                               hdrlen -= LOW(ntohs(*optdesc));
-                               DEBUGP("len%04X \n", 
-                                       LOW(ntohs(*optdesc)));
+                               DEBUGP("Pad1\n");
+                               optlen = 1;
                        }
-                       if (ptr > skb->len || ( !hdrlen && 
-                               (temp != optinfo->optsnr - 1))) {
+
+                       /* Step to the next */
+                       DEBUGP("len%04X \n", optlen);
+
+                       if ((ptr > skb->len - optlen || hdrlen < optlen) &&
+                           (temp < optinfo->optsnr - 1)) {
                                DEBUGP("new pointer is too large! \n");
                                break;
                        }
+                       ptr += optlen;
+                       hdrlen -= optlen;
                }
                if (temp == optinfo->optsnr)
                        return ret;
@@ -271,6 +281,7 @@ static struct ip6t_match opts_match = {
 #endif
        .match          = &match,
        .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
 };
 
 static int __init init(void)
index ecdd48b..e39dd23 100644 (file)
@@ -32,8 +32,8 @@ static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
 {
        int r=0;
-        DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
-               min,spi,max);
+       DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+              min,spi,max);
        r=(spi >= min && spi <= max) ^ invert;
        DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
        return r;
@@ -45,11 +45,10 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *protohdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
-       struct ip_esp_hdr *esp = NULL;
+       struct ip_esp_hdr _esp, *eh = NULL;
        const struct ip6t_esp *espinfo = matchinfo;
        unsigned int temp;
        int len;
@@ -67,73 +66,74 @@ match(const struct sk_buff *skb,
        len = skb->len - ptr;
        temp = 0;
 
-        while (ip6t_ext_hdr(nexthdr)) {
-               struct ipv6_opt_hdr *hdr;
-               int hdrlen;
+       while (ip6t_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr _hdr, *hp;
+               int hdrlen;
 
                DEBUGP("ipv6_esp header iteration \n");
 
                /* Is there enough space for the next ext header? */
-                if (len < (int)sizeof(struct ipv6_opt_hdr))
-                        return 0;
+               if (len < sizeof(struct ipv6_opt_hdr))
+                       return 0;
                /* No more exthdr -> evaluate */
-                if (nexthdr == NEXTHDR_NONE) {
+               if (nexthdr == NEXTHDR_NONE)
                        break;
-               }
                /* ESP -> evaluate */
-                if (nexthdr == NEXTHDR_ESP) {
+               if (nexthdr == NEXTHDR_ESP) {
                        temp |= MASK_ESP;
                        break;
                }
 
-               hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+               hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
+               BUG_ON(hp == NULL);
 
                /* Calculate the header length */
-                if (nexthdr == NEXTHDR_FRAGMENT) {
-                        hdrlen = 8;
-                } else if (nexthdr == NEXTHDR_AUTH)
-                        hdrlen = (hdr->hdrlen+2)<<2;
-                else
-                        hdrlen = ipv6_optlen(hdr);
+               if (nexthdr == NEXTHDR_FRAGMENT)
+                       hdrlen = 8;
+               else if (nexthdr == NEXTHDR_AUTH)
+                       hdrlen = (hp->hdrlen+2)<<2;
+               else
+                       hdrlen = ipv6_optlen(hp);
 
                /* set the flag */
-               switch (nexthdr){
-                       case NEXTHDR_HOP:
-                       case NEXTHDR_ROUTING:
-                       case NEXTHDR_FRAGMENT:
-                       case NEXTHDR_AUTH:
-                       case NEXTHDR_DEST:
-                               break;
-                       default:
-                               DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr);
-                               return 0;
-                               break;
+               switch (nexthdr) {
+               case NEXTHDR_HOP:
+               case NEXTHDR_ROUTING:
+               case NEXTHDR_FRAGMENT:
+               case NEXTHDR_AUTH:
+               case NEXTHDR_DEST:
+                       break;
+               default:
+                       DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr);
+                       return 0;
                }
 
-                nexthdr = hdr->nexthdr;
-                len -= hdrlen;
-                ptr += hdrlen;
-               if ( ptr > skb->len ) {
+               nexthdr = hp->nexthdr;
+               len -= hdrlen;
+               ptr += hdrlen;
+               if (ptr > skb->len) {
                        DEBUGP("ipv6_esp: new pointer too large! \n");
                        break;
                }
-        }
+       }
 
        /* ESP header not found */
-       if ( temp != MASK_ESP ) return 0;
+       if (temp != MASK_ESP)
+               return 0;
 
-       if (len < (int)sizeof(struct ip_esp_hdr)){
-              *hotdrop = 1;
-                       return 0;
-       }
+       if (len < sizeof(struct ip_esp_hdr)) {
+               *hotdrop = 1;
+               return 0;
+       }
 
-       esp = (struct ip_esp_hdr *) (skb->data + ptr);
+       eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp);
+       BUG_ON(eh == NULL);
 
-       DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi));
+       DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi));
 
-       return (esp != NULL)
+       return (eh != NULL)
                && spi_match(espinfo->spis[0], espinfo->spis[1],
-                             ntohl(esp->spi),
+                             ntohl(eh->spi),
                              !!(espinfo->invflags & IP6T_ESP_INV_SPI));
 }
 
@@ -157,7 +157,6 @@ checkentry(const char *tablename,
                         espinfo->invflags);
                return 0;
        }
-
        return 1;
 }
 
index 3b1340d..616c2cb 100644 (file)
@@ -24,8 +24,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *hdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
 
@@ -70,7 +69,7 @@ ip6t_eui64_checkentry(const char *tablename,
 {
        if (hook_mask
            & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
-               (1 << NF_IP6_PRE_ROUTING) )) {
+               (1 << NF_IP6_FORWARD))) {
                printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
                return 0;
        }
index d6eabaa..4bfa30a 100644 (file)
@@ -14,8 +14,6 @@
 #include <net/checksum.h>
 #include <net/ipv6.h>
 
-#include <asm/byteorder.h>
-
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_frag.h>
 
@@ -29,29 +27,6 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
 #define DEBUGP(format, args...)
 #endif
 
-#if 0
-#if     BYTE_ORDER == BIG_ENDIAN
-#define IP6F_OFF_MASK       0xfff8  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0006  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0001  /* more-fragments flag */
-#else   /* BYTE_ORDER == LITTLE_ENDIAN */
-#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
-#endif
-#endif
-
-#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
-
-struct fraghdr {
-       __u8    nexthdr;
-       __u8    hdrlen;
-       __u16   info;
-       __u32   id;
-};
-
 /* Returns 1 if the id is matched by the range, 0 otherwise */
 static inline int
 id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
@@ -70,11 +45,10 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *protohdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
-       struct fraghdr *frag = NULL;
+       struct frag_hdr _frag, *fh = NULL;
        const struct ip6t_frag *fraginfo = matchinfo;
        unsigned int temp;
        int len;
@@ -91,7 +65,7 @@ match(const struct sk_buff *skb,
        temp = 0;
 
         while (ip6t_ext_hdr(nexthdr)) {
-               struct ipv6_opt_hdr *hdr;
+               struct ipv6_opt_hdr _hdr, *hp;
 
               DEBUGP("ipv6_frag header iteration \n");
 
@@ -107,15 +81,16 @@ match(const struct sk_buff *skb,
                      break;
               }
 
-              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+             hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
+             BUG_ON(hp == NULL);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
                         hdrlen = 8;
                 } else if (nexthdr == NEXTHDR_AUTH)
-                        hdrlen = (hdr->hdrlen+2)<<2;
+                        hdrlen = (hp->hdrlen+2)<<2;
                 else
-                        hdrlen = ipv6_optlen(hdr);
+                        hdrlen = ipv6_optlen(hp);
 
               /* FRAG -> evaluate */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -138,7 +113,7 @@ match(const struct sk_buff *skb,
                             break;
               }
 
-                nexthdr = hdr->nexthdr;
+                nexthdr = hp->nexthdr;
                 len -= hdrlen;
                 ptr += hdrlen;
                if ( ptr > skb->len ) {
@@ -150,59 +125,63 @@ match(const struct sk_buff *skb,
        /* FRAG header not found */
        if ( temp != MASK_FRAGMENT ) return 0;
 
-       if (len < (int)sizeof(struct fraghdr)){
+       if (len < sizeof(struct frag_hdr)){
               *hotdrop = 1;
                        return 0;
        }
 
-       frag = (struct fraghdr *) (skb->data + ptr);
+       fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
+       BUG_ON(fh == NULL);
 
-       DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen);
-       DEBUGP("INFO %04X ", frag->info);
-       DEBUGP("OFFSET %04X ", frag->info & IP6F_OFF_MASK);
-       DEBUGP("RES %04X ", frag->info & IP6F_RESERVED_MASK);
-       DEBUGP("MF %04X ", frag->info & IP6F_MORE_FRAG);
-       DEBUGP("ID %u %08X\n", ntohl(frag->id), ntohl(frag->id));
+       DEBUGP("INFO %04X ", fh->frag_off);
+       DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7);
+       DEBUGP("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6);
+       DEBUGP("MF %04X ", fh->frag_off & htons(IP6_MF));
+       DEBUGP("ID %u %08X\n", ntohl(fh->identification),
+             ntohl(fh->identification));
 
        DEBUGP("IPv6 FRAG id %02X ",
                        (id_match(fraginfo->ids[0], fraginfo->ids[1],
-                           ntohl(frag->id),
+                           ntohl(fh->identification),
                            !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
-       DEBUGP("len %02X %04X %02X ",
-                       fraginfo->hdrlen, hdrlen,
-                       (!fraginfo->hdrlen ||
-                           (fraginfo->hdrlen == hdrlen) ^
-                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN)));
-       DEBUGP("res %02X %02X %02X ", 
-                       (fraginfo->flags & IP6T_FRAG_RES), frag->info & IP6F_RESERVED_MASK,
-                       !((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK)));
+       DEBUGP("res %02X %02X%04X %02X ", 
+                       (fraginfo->flags & IP6T_FRAG_RES), fh->reserved,
+               ntohs(fh->frag_off) & 0x6,
+                       !((fraginfo->flags & IP6T_FRAG_RES)
+                       && (fh->reserved || (ntohs(fh->frag_off) & 0x06))));
        DEBUGP("first %02X %02X %02X ", 
-                       (fraginfo->flags & IP6T_FRAG_FST), frag->info & IP6F_OFF_MASK,
-                       !((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK)));
+                       (fraginfo->flags & IP6T_FRAG_FST),
+               ntohs(fh->frag_off) & ~0x7,
+                       !((fraginfo->flags & IP6T_FRAG_FST)
+                       && (ntohs(fh->frag_off) & ~0x7)));
        DEBUGP("mf %02X %02X %02X ", 
-                       (fraginfo->flags & IP6T_FRAG_MF), frag->info & IP6F_MORE_FRAG,
-                       !((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG))));
+                       (fraginfo->flags & IP6T_FRAG_MF),
+               ntohs(fh->frag_off) & IP6_MF,
+                       !((fraginfo->flags & IP6T_FRAG_MF)
+                       && !((ntohs(fh->frag_off) & IP6_MF))));
        DEBUGP("last %02X %02X %02X\n", 
-                       (fraginfo->flags & IP6T_FRAG_NMF), frag->info & IP6F_MORE_FRAG,
-                       !((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG)));
+                       (fraginfo->flags & IP6T_FRAG_NMF),
+               ntohs(fh->frag_off) & IP6_MF,
+                       !((fraginfo->flags & IP6T_FRAG_NMF)
+                       && (ntohs(fh->frag_off) & IP6_MF)));
 
-       return (frag != NULL)
+       return (fh != NULL)
                        &&
                        (id_match(fraginfo->ids[0], fraginfo->ids[1],
-                           ntohl(frag->id),
+                         ntohl(fh->identification),
                            !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
                &&
-               (!fraginfo->hdrlen ||
-                           (fraginfo->hdrlen == hdrlen) ^
-                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN))
-               &&
-               !((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK))
+               !((fraginfo->flags & IP6T_FRAG_RES)
+                       && (fh->reserved || (ntohs(fh->frag_off) & 0x6)))
                &&
-               !((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK))
+               !((fraginfo->flags & IP6T_FRAG_FST)
+                       && (ntohs(fh->frag_off) & ~0x7))
                &&
-               !((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG)))
+               !((fraginfo->flags & IP6T_FRAG_MF)
+                       && !(ntohs(fh->frag_off) & IP6_MF))
                &&
-               !((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG));
+               !((fraginfo->flags & IP6T_FRAG_NMF)
+                       && (ntohs(fh->frag_off) & IP6_MF));
 }
 
 /* Called when user tries to insert an entry of this type. */
index 6849122..27f3650 100644 (file)
@@ -19,8 +19,6 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_opts.h>
 
-#define LOW(n)         (n & 0x00FF)
-
 #define HOPBYHOP       1
 
 MODULE_LICENSE("GPL");
@@ -47,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
  *     0       -> invariant
  *     1       -> can change the routing
  *  (Type & 0x1F) Type
- *      0      -> PAD0 (only 1 byte!)
- *      1      -> PAD1 LENGTH info (total length = length + 2)
+ *      0      -> Pad1 (only 1 byte!)
+ *      1      -> PadN LENGTH info (total length = length + 2)
  *      C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
  *      5      -> RTALERT 2 x x
  */
@@ -59,11 +57,10 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *protohdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
-       struct ipv6_opt_hdr *optsh = NULL;
+       struct ipv6_opt_hdr _optsh, *oh;
        const struct ip6t_opts *optinfo = matchinfo;
        unsigned int temp;
        unsigned int len;
@@ -71,7 +68,9 @@ match(const struct sk_buff *skb,
        unsigned int ptr;
        unsigned int hdrlen = 0;
        unsigned int ret = 0;
-       u_int16_t *optdesc = NULL;
+       u8 _opttype, *tp = NULL;
+       u8 _optlen, *lp = NULL;
+       unsigned int optlen;
        
        /* type of the 1st exthdr */
        nexthdr = skb->nh.ipv6h->nexthdr;
@@ -82,7 +81,7 @@ match(const struct sk_buff *skb,
        temp = 0;
 
         while (ip6t_ext_hdr(nexthdr)) {
-               struct ipv6_opt_hdr *hdr;
+               struct ipv6_opt_hdr _hdr, *hp;
 
               DEBUGP("ipv6_opts header iteration \n");
 
@@ -98,15 +97,16 @@ match(const struct sk_buff *skb,
                      break;
               }
 
-              hdr=(void *)(skb->data)+ptr;
+             hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
+             BUG_ON(hp == NULL);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
                         hdrlen = 8;
                 } else if (nexthdr == NEXTHDR_AUTH)
-                        hdrlen = (hdr->hdrlen+2)<<2;
+                        hdrlen = (hp->hdrlen+2)<<2;
                 else
-                        hdrlen = ipv6_optlen(hdr);
+                        hdrlen = ipv6_optlen(hp);
 
               /* OPTS -> evaluate */
 #if HOPBYHOP
@@ -134,7 +134,7 @@ match(const struct sk_buff *skb,
                             break;
               }
 
-                nexthdr = hdr->nexthdr;
+                nexthdr = hp->nexthdr;
                 len -= hdrlen;
                 ptr += hdrlen;
                if ( ptr > skb->len ) {
@@ -160,9 +160,10 @@ match(const struct sk_buff *skb,
                        return 0;
        }
 
-       optsh=(void *)(skb->data)+ptr;
+       oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
+       BUG_ON(oh == NULL);
 
-       DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
+       DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
 
        DEBUGP("len %02X %04X %02X ",
                        optinfo->hdrlen, hdrlen,
@@ -170,13 +171,12 @@ match(const struct sk_buff *skb,
                            ((optinfo->hdrlen == hdrlen) ^
                            !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
 
-       ret = (optsh != NULL)
+       ret = (oh != NULL)
                        &&
                (!(optinfo->flags & IP6T_OPTS_LEN) ||
                            ((optinfo->hdrlen == hdrlen) ^
                            !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
 
-       temp = len = 0;
        ptr += 2;
        hdrlen -= 2;
        if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
@@ -187,48 +187,59 @@ match(const struct sk_buff *skb,
                DEBUGP("Strict ");
                DEBUGP("#%d ",optinfo->optsnr);
                for(temp=0; temp<optinfo->optsnr; temp++){
-                       optdesc = (void *)(skb->data)+ptr;
+                       /* type field exists ? */
+                       if (hdrlen < 1)
+                               break;
+                       tp = skb_header_pointer(skb, ptr, sizeof(_opttype),
+                                               &_opttype);
+                       if (tp == NULL)
+                               break;
+
                        /* Type check */
-                       if ( (unsigned char)*optdesc != 
-                               (optinfo->opts[temp] & 0xFF00)>>8 ){
+                       if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){
                                DEBUGP("Tbad %02X %02X\n",
-                                               (unsigned char)*optdesc,
-                                               (optinfo->opts[temp] &
-                                                0xFF00)>>8);
+                                      *tp,
+                                      (optinfo->opts[temp] & 0xFF00)>>8);
                                return 0;
                        } else {
                                DEBUGP("Tok ");
                        }
                        /* Length check */
-                       if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
-                               (unsigned char)*optdesc != 0){
-                               if ( ntohs((u16)*optdesc) != 
-                                               optinfo->opts[temp] ){
-                                       DEBUGP("Lbad %02X %04X %04X\n",
-                                                       (unsigned char)*optdesc,
-                                                       ntohs((u16)*optdesc),
-                                                       optinfo->opts[temp]);
+                       if (*tp) {
+                               u16 spec_len;
+
+                               /* length field exists ? */
+                               if (hdrlen < 2)
+                                       break;
+                               lp = skb_header_pointer(skb, ptr + 1,
+                                                       sizeof(_optlen),
+                                                       &_optlen);
+                               if (lp == NULL)
+                                       break;
+                               spec_len = optinfo->opts[temp] & 0x00FF;
+
+                               if (spec_len != 0x00FF && spec_len != *lp) {
+                                       DEBUGP("Lbad %02X %04X\n", *lp,
+                                              spec_len);
                                        return 0;
-                               } else {
-                                       DEBUGP("Lok ");
                                }
-                       }
-                       /* Step to the next */
-                       if ((unsigned char)*optdesc == 0){
-                               DEBUGP("PAD0 \n");
-                               ptr++;
-                               hdrlen--;
+                               DEBUGP("Lok ");
+                               optlen = *lp + 2;
                        } else {
-                               ptr += LOW(ntohs(*optdesc));
-                               hdrlen -= LOW(ntohs(*optdesc));
-                               DEBUGP("len%04X \n", 
-                                       LOW(ntohs(*optdesc)));
+                               DEBUGP("Pad1\n");
+                               optlen = 1;
                        }
-                       if (ptr > skb->len || ( !hdrlen && 
-                               (temp != optinfo->optsnr - 1))) {
+
+                       /* Step to the next */
+                       DEBUGP("len%04X \n", optlen);
+
+                       if ((ptr > skb->len - optlen || hdrlen < optlen) &&
+                           (temp < optinfo->optsnr - 1)) {
                                DEBUGP("new pointer is too large! \n");
                                break;
                        }
+                       ptr += optlen;
+                       hdrlen -= optlen;
                }
                if (temp == optinfo->optsnr)
                        return ret;
index e538f14..0beaff5 100644 (file)
@@ -20,7 +20,7 @@ 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, const void *hdr, u_int16_t datalen,
+                int offset, unsigned int protoff,
                 int *hotdrop)
 {
        const struct ip6t_hl_info *info = matchinfo;
index ae5d1c6..32e67f0 100644 (file)
@@ -31,8 +31,7 @@ ipv6header_match(const struct sk_buff *skb,
                 const struct net_device *out,
                 const void *matchinfo,
                 int offset,
-                const void *protohdr,
-                u_int16_t datalen,
+                unsigned int protoff,
                 int *hotdrop)
 {
        const struct ip6t_ipv6header_info *info = matchinfo;
@@ -52,7 +51,7 @@ ipv6header_match(const struct sk_buff *skb,
        temp = 0;
 
         while (ip6t_ext_hdr(nexthdr)) {
-               struct ipv6_opt_hdr *hdr;
+               struct ipv6_opt_hdr _hdr, *hp;
                int hdrlen;
 
                /* Is there enough space for the next ext header? */
@@ -69,15 +68,16 @@ ipv6header_match(const struct sk_buff *skb,
                        break;
                }
 
-               hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+               hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
+               BUG_ON(hp == NULL);
 
                /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
                         hdrlen = 8;
                 } else if (nexthdr == NEXTHDR_AUTH)
-                        hdrlen = (hdr->hdrlen+2)<<2;
+                        hdrlen = (hp->hdrlen+2)<<2;
                 else
-                        hdrlen = ipv6_optlen(hdr);
+                        hdrlen = ipv6_optlen(hp);
 
                /* set the flag */
                switch (nexthdr){
@@ -101,7 +101,7 @@ ipv6header_match(const struct sk_buff *skb,
                                break;
                }
 
-                nexthdr = hdr->nexthdr;
+                nexthdr = hp->nexthdr;
                 len -= hdrlen;
                 ptr += hdrlen;
                if (ptr > skb->len)
@@ -112,10 +112,14 @@ ipv6header_match(const struct sk_buff *skb,
                temp |= MASK_PROTO;
 
        if (info->modeflag)
-               return (!( (temp & info->matchflags)
-                       ^ info->matchflags) ^ info->invflags);
-       else
-               return (!( temp ^ info->matchflags) ^ info->invflags);
+               return !((temp ^ info->matchflags ^ info->invflags)
+                        & info->matchflags);
+       else {
+               if (info->invflags)
+                       return temp != info->matchflags;
+               else
+                       return temp == info->matchflags;
+       }
 }
 
 static int
@@ -125,11 +129,18 @@ ipv6header_checkentry(const char *tablename,
                      unsigned int matchsize,
                      unsigned int hook_mask)
 {
+       const struct ip6t_ipv6header_info *info = matchinfo;
+
        /* Check for obvious errors */
        /* This match is valid in all hooks! */
        if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)))
                return 0;
 
+       /* invflags is 0 or 0xff in hard mode */
+       if ((!info->modeflag) && info->invflags != 0x00
+                             && info->invflags != 0xFF)
+               return 0;
+
        return 1;
 }
 
index 5a86722..e0537d3 100644 (file)
@@ -23,8 +23,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *hdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
        const struct ip6t_length_info *info = matchinfo;
index 4780c3a..a462b77 100644 (file)
@@ -57,8 +57,7 @@ ip6t_limit_match(const struct sk_buff *skb,
                const struct net_device *out,
                const void *matchinfo,
                int offset,
-               const void *hdr,
-               u_int16_t datalen,
+               unsigned int protoff,
                int *hotdrop)
 {
        struct ip6t_rateinfo *r = ((struct ip6t_rateinfo *)matchinfo)->master;
index ea874dd..526d43e 100644 (file)
@@ -25,8 +25,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *hdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
     const struct ip6t_mac_info *info = matchinfo;
index dc8484e..affc3de 100644 (file)
@@ -24,8 +24,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *hdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
        const struct ip6t_mark_info *info = matchinfo;
index 7250415..6e32461 100644 (file)
@@ -53,28 +53,32 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *hdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
-       const struct udphdr *udp = hdr;
+       u16 _ports[2], *pptr;
        const struct ip6t_multiport *multiinfo = matchinfo;
 
-       /* Must be big enough to read ports. */
-       if (offset == 0 && datalen < sizeof(struct udphdr)) {
+       /* Must not be a fragment. */
+       if (offset)
+               return 0;
+
+       /* Must be big enough to read ports (both UDP and TCP have
+          them at the start). */
+       pptr = skb_header_pointer(skb, protoff, sizeof(_ports), &_ports[0]);
+       if (pptr == NULL) {
                /* We've been asked to examine this packet, and we
-                  can't.  Hence, no choice but to drop. */
-                       duprintf("ip6t_multiport:"
-                                " Dropping evil offset=0 tinygram.\n");
-                       *hotdrop = 1;
-                       return 0;
+                * can't.  Hence, no choice but to drop.
+                */
+               duprintf("ip6t_multiport:"
+                        " Dropping evil offset=0 tinygram.\n");
+               *hotdrop = 1;
+               return 0;
        }
 
-       /* Must not be a fragment. */
-       return !offset
-               && ports_match(multiinfo->ports,
-                              multiinfo->flags, multiinfo->count,
-                              ntohs(udp->source), ntohs(udp->dest));
+       return ports_match(multiinfo->ports,
+                          multiinfo->flags, multiinfo->count,
+                          ntohs(pptr[0]), ntohs(pptr[1]));
 }
 
 /* Called when user tries to insert an entry of this type. */
@@ -87,9 +91,12 @@ checkentry(const char *tablename,
 {
        const struct ip6t_multiport *multiinfo = matchinfo;
 
+       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport)))
+               return 0;
+
        /* Must specify proto == TCP/UDP, no unknown flags or bad count */
        return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
-               && !(ip->flags & IP6T_INV_PROTO)
+               && !(ip->invflags & IP6T_INV_PROTO)
                && matchsize == IP6T_ALIGN(sizeof(struct ip6t_multiport))
                && (multiinfo->flags == IP6T_MULTIPORT_SOURCE
                    || multiinfo->flags == IP6T_MULTIPORT_DESTINATION
index f4eebb4..71515c8 100644 (file)
@@ -26,8 +26,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *hdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
        int i;
index f444ed9..a9526b7 100644 (file)
@@ -47,11 +47,10 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
-      const void *protohdr,
-      u_int16_t datalen,
+      unsigned int protoff,
       int *hotdrop)
 {
-       struct ipv6_rt_hdr *route = NULL;
+       struct ipv6_rt_hdr _route, *rh = NULL;
        const struct ip6t_rt *rtinfo = matchinfo;
        unsigned int temp;
        unsigned int len;
@@ -59,6 +58,7 @@ match(const struct sk_buff *skb,
        unsigned int ptr;
        unsigned int hdrlen = 0;
        unsigned int ret = 0;
+       struct in6_addr *ap, _addr;
 
        /* type of the 1st exthdr */
        nexthdr = skb->nh.ipv6h->nexthdr;
@@ -69,7 +69,7 @@ match(const struct sk_buff *skb,
        temp = 0;
 
         while (ip6t_ext_hdr(nexthdr)) {
-               struct ipv6_opt_hdr *hdr;
+               struct ipv6_opt_hdr _hdr, *hp;
 
               DEBUGP("ipv6_rt header iteration \n");
 
@@ -85,15 +85,16 @@ match(const struct sk_buff *skb,
                      break;
               }
 
-              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+             hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
+             BUG_ON(hp == NULL);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
                         hdrlen = 8;
                 } else if (nexthdr == NEXTHDR_AUTH)
-                        hdrlen = (hdr->hdrlen+2)<<2;
+                        hdrlen = (hp->hdrlen+2)<<2;
                 else
-                        hdrlen = ipv6_optlen(hdr);
+                        hdrlen = ipv6_optlen(hp);
 
               /* ROUTING -> evaluate */
                 if (nexthdr == NEXTHDR_ROUTING) {
@@ -116,7 +117,7 @@ match(const struct sk_buff *skb,
                             break;
               }
 
-                nexthdr = hdr->nexthdr;
+                nexthdr = hp->nexthdr;
                 len -= hdrlen;
                 ptr += hdrlen;
                if ( ptr > skb->len ) {
@@ -138,20 +139,21 @@ match(const struct sk_buff *skb,
                        return 0;
        }
 
-       route = (struct ipv6_rt_hdr *) (skb->data + ptr);
+       rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
+       BUG_ON(rh == NULL);
 
-       DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
-       DEBUGP("TYPE %04X ", route->type);
-       DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left));
+       DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
+       DEBUGP("TYPE %04X ", rh->type);
+       DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);
 
        DEBUGP("IPv6 RT segsleft %02X ",
                        (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
-                           ntohl(route->segments_left),
+                           rh->segments_left,
                            !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
        DEBUGP("type %02X %02X %02X ",
-                       rtinfo->rt_type, route->type, 
+                       rtinfo->rt_type, rh->type, 
                        (!(rtinfo->flags & IP6T_RT_TYP) ||
-                           ((rtinfo->rt_type == route->type) ^
+                           ((rtinfo->rt_type == rh->type) ^
                            !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
        DEBUGP("len %02X %04X %02X ",
                        rtinfo->hdrlen, hdrlen,
@@ -159,13 +161,13 @@ match(const struct sk_buff *skb,
                            ((rtinfo->hdrlen == hdrlen) ^
                            !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
        DEBUGP("res %02X %02X %02X ", 
-                       (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap,
-                       !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)));
+                       (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)rh)->bitmap,
+                       !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)rh)->bitmap)));
 
-       ret = (route != NULL)
+       ret = (rh != NULL)
                        &&
                        (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
-                           ntohl(route->segments_left),
+                           rh->segments_left,
                            !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
                &&
                (!(rtinfo->flags & IP6T_RT_LEN) ||
@@ -173,13 +175,19 @@ match(const struct sk_buff *skb,
                            !!(rtinfo->invflags & IP6T_RT_INV_LEN)))
                &&
                        (!(rtinfo->flags & IP6T_RT_TYP) ||
-                           ((rtinfo->rt_type == route->type) ^
-                           !!(rtinfo->invflags & IP6T_RT_INV_TYP)))
-               &&
-                       !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap));
+                           ((rtinfo->rt_type == rh->type) ^
+                           !!(rtinfo->invflags & IP6T_RT_INV_TYP)));
+
+       if (ret && (rtinfo->flags & IP6T_RT_RES)) {
+               u_int32_t *bp, _bitmap;
+               bp = skb_header_pointer(skb,
+                                       ptr + offsetof(struct rt0_hdr, bitmap),
+                                       sizeof(_bitmap), &_bitmap);
+
+               ret = (*bp == 0);
+       }
 
        DEBUGP("#%d ",rtinfo->addrnr);
-       temp = len = ptr = 0;
        if ( !(rtinfo->flags & IP6T_RT_FST) ){
               return ret;
        } else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
@@ -188,32 +196,27 @@ match(const struct sk_buff *skb,
                        DEBUGP("There isn't enough space\n");
                        return 0;
                } else {
+                       unsigned int i = 0;
+
                        DEBUGP("#%d ",rtinfo->addrnr);
-                       ptr = 0;
                        for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){
-                               len = 0;
-                               while ((u8)(((struct rt0_hdr *)route)->
-                                               addr[temp].s6_addr[len]) ==
-                                       (u8)(rtinfo->addrs[ptr].s6_addr[len])){
-                                       DEBUGP("%02X?%02X ",
-               (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
-                                       (u8)(rtinfo->addrs[ptr].s6_addr[len]));
-                                       len++;
-                                       if ( len == 16 ) break;
-                               }
-                               if (len==16) {
-                                       DEBUGP("ptr=%d temp=%d;\n",ptr,temp);
-                                       ptr++;
-                               } else {
-                                       DEBUGP("%02X?%02X ",
-               (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
-                                       (u8)(rtinfo->addrs[ptr].s6_addr[len]));
-                                       DEBUGP("!ptr=%d temp=%d;\n",ptr,temp);
+                               ap = skb_header_pointer(skb,
+                                                       ptr
+                                                       + sizeof(struct rt0_hdr)
+                                                       + temp * sizeof(_addr),
+                                                       sizeof(_addr),
+                                                       &_addr);
+
+                               BUG_ON(ap == NULL);
+
+                               if (ipv6_addr_equal(ap, &rtinfo->addrs[i])) {
+                                       DEBUGP("i=%d temp=%d;\n",i,temp);
+                                       i++;
                                }
-                               if (ptr==rtinfo->addrnr) break;
+                               if (i==rtinfo->addrnr) break;
                        }
-                       DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr);
-                       if ( (len == 16) && (ptr == rtinfo->addrnr))
+                       DEBUGP("i=%d #%d\n", i, rtinfo->addrnr);
+                       if (i == rtinfo->addrnr)
                                return ret;
                        else return 0;
                }
@@ -225,26 +228,19 @@ match(const struct sk_buff *skb,
                } else {
                        DEBUGP("#%d ",rtinfo->addrnr);
                        for(temp=0; temp<rtinfo->addrnr; temp++){
-                               len = 0;
-                               while ((u8)(((struct rt0_hdr *)route)->
-                                               addr[temp].s6_addr[len]) ==
-                                       (u8)(rtinfo->addrs[temp].s6_addr[len])){
-                                       DEBUGP("%02X?%02X ",
-               (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
-                                       (u8)(rtinfo->addrs[temp].s6_addr[len]));
-                                       len++;
-                                       if ( len == 16 ) break;
-                               }
-                               if (len!=16) {
-                                       DEBUGP("%02X?%02X ",
-               (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
-                                       (u8)(rtinfo->addrs[temp].s6_addr[len]));
-                                       DEBUGP("!len=%d temp=%d;\n",len,temp);
+                               ap = skb_header_pointer(skb,
+                                                       ptr
+                                                       + sizeof(struct rt0_hdr)
+                                                       + temp * sizeof(_addr),
+                                                       sizeof(_addr),
+                                                       &_addr);
+                               BUG_ON(ap == NULL);
+
+                               if (!ipv6_addr_equal(ap, &rtinfo->addrs[temp]))
                                        break;
-                               }
                        }
-                       DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr);
-                       if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
+                       DEBUGP("temp=%d #%d\n", temp, rtinfo->addrnr);
+                       if ((temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
                                return ret;
                        else return 0;
                }
index 40612ec..b06b11c 100644 (file)
@@ -79,7 +79,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
        int mtu, ret = 0;
        struct dst_entry *dst = skb->dst;
 
-       mtu = dst_pmtu(dst) - sizeof(struct ipv6hdr);
+       mtu = dst_pmtu(dst) - dst->header_len - dst->trailer_len;
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
 
@@ -91,16 +91,14 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
        return ret;
 }
 
-int xfrm6_output(struct sk_buff **pskb)
+int xfrm6_output(struct sk_buff *skb)
 {
-       struct sk_buff *skb = *pskb;
        struct dst_entry *dst = skb->dst;
        struct xfrm_state *x = dst->xfrm;
        int err;
        
        if (skb->ip_summed == CHECKSUM_HW) {
-               err = skb_checksum_help(pskb, 0);
-               skb = *pskb;
+               err = skb_checksum_help(skb, 0);
                if (err)
                        goto error_nolock;
        }
index fa066ee..fb99913 100644 (file)
@@ -143,12 +143,6 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
 
        ircomm_tty_ias_register(self);
 
-       /* Check if somebody has already connected to us */
-       if (ircomm_is_connected(self->ircomm)) {
-               IRDA_DEBUG(0, "%s(), already connected!\n", __FUNCTION__ );
-               return 0;
-       }
-
        ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);
 
        return 0;
@@ -169,9 +163,16 @@ void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
 
        del_timer(&self->watchdog_timer);
 
+       /* Remove discovery handler */
+       if (self->ckey) {
+               irlmp_unregister_client(self->ckey);
+               self->ckey = NULL;
+       }
        /* Remove IrCOMM hint bits */
-       irlmp_unregister_client(self->ckey);
-       irlmp_unregister_service(self->skey);
+       if (self->skey) {
+               irlmp_unregister_service(self->skey);
+               self->skey = NULL;
+       }
 
        if (self->iriap) { 
                iriap_close(self->iriap);
@@ -209,18 +210,30 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
        
+       /* Compute hint bits based on service */
+       hints = irlmp_service_to_hint(S_COMM);
+       if (self->service_type & IRCOMM_3_WIRE_RAW)
+               hints |= irlmp_service_to_hint(S_PRINTER);
+
+       /* Advertise IrCOMM hint bit in discovery */
+       if (!self->skey)
+               self->skey = irlmp_register_service(hints);
+       /* Set up a discovery handler */
+       if (!self->ckey)
+               self->ckey = irlmp_register_client(hints,
+                                                  ircomm_tty_discovery_indication,
+                                                  NULL, (void *) self);
+
+       /* If already done, no need to do it again */
+       if (self->obj)
+               return;
+
        if (self->service_type & IRCOMM_3_WIRE_RAW) {
-               hints = irlmp_service_to_hint(S_PRINTER);
-               hints |= irlmp_service_to_hint(S_COMM);
-               
                /* Register IrLPT with LM-IAS */
                self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
                irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel", 
                                         self->slsap_sel, IAS_KERNEL_ATTR);
-               irias_insert_object(self->obj);
        } else {
-               hints = irlmp_service_to_hint(S_COMM);
-
                /* Register IrCOMM with LM-IAS */
                self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);
                irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel", 
@@ -234,12 +247,45 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
                /* Register parameters with LM-IAS */
                irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,
                                        IAS_KERNEL_ATTR);
-               irias_insert_object(self->obj);
        }
-       self->skey = irlmp_register_service(hints);
-       self->ckey = irlmp_register_client(hints,
-                                          ircomm_tty_discovery_indication,
-                                          NULL, (void *) self);
+       irias_insert_object(self->obj);
+}
+
+/*
+ * Function ircomm_tty_ias_unregister (self)
+ *
+ *    Remove our IAS object and client hook while connected.
+ *
+ */
+static void ircomm_tty_ias_unregister(struct ircomm_tty_cb *self)
+{
+       /* Remove LM-IAS object now so it is not reused.
+        * IrCOMM deals very poorly with multiple incoming connections.
+        * It should looks a lot more like IrNET, and "dup" a server TSAP
+        * to the application TSAP (based on various rules).
+        * This is a cheap workaround allowing multiple clients to
+        * connect to us. It will not always work.
+        * Each IrCOMM socket has an IAS entry. Incoming connection will
+        * pick the first one found. So, when we are fully connected,
+        * we remove our IAS entries so that the next IAS entry is used.
+        * We do that for *both* client and server, because a server
+        * can also create client instances.
+        * Jean II */
+       if (self->obj) {
+               irias_delete_object(self->obj);
+               self->obj = NULL;
+       }
+
+#if 0
+       /* Remove discovery handler.
+        * While we are connected, we no longer need to receive
+        * discovery events. This would be the case if there is
+        * multiple IrLAP interfaces. Jean II */
+       if (self->ckey) {
+               irlmp_unregister_client(self->ckey);
+               self->ckey = NULL;
+       }
+#endif
 }
 
 /*
@@ -333,7 +379,8 @@ static void ircomm_tty_discovery_indication(discinfo_t *discovery,
        info.daddr = discovery->daddr;
        info.saddr = discovery->saddr;
 
-       /* FIXME. We probably need to use hashbin_find_next(), but we first
+       /* FIXME. We have a locking problem on the hashbin here.
+        * We probably need to use hashbin_find_next(), but we first
         * need to ensure that "line" is unique. - Jean II */
        self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
        while (self != NULL) {
@@ -519,23 +566,6 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
        
        del_timer(&self->watchdog_timer);
 
-       /* Remove LM-IAS object now so it is not reused.
-        * IrCOMM deals very poorly with multiple incoming connections.
-        * It should looks a lot more like IrNET, and "dup" a server TSAP
-        * to the application TSAP (based on various rules).
-        * This is a cheap workaround allowing multiple clients to
-        * connect to us. It will not always work.
-        * Each IrCOMM socket has an IAS entry. Incoming connection will
-        * pick the first one found. So, when we are fully connected,
-        * we remove our IAS entries so that the next IAS entry is used.
-        * We do that for *both* client and server, because a server
-        * can also create client instances.
-        * Jean II */
-       if (self->obj) {
-               irias_delete_object(self->obj);
-               self->obj = NULL;
-       }
-
        /* 
         * IrCOMM link is now up, and if we are not using hardware
         * flow-control, then declare the hardware as running. Otherwise we
@@ -558,7 +588,7 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
 }
 
 /*
- * Function irlan_start_watchdog_timer (self, timeout)
+ * Function ircomm_tty_start_watchdog_timer (self, timeout)
  *
  *    Start the watchdog timer. This timer is used to make sure that any 
  *    connection attempt is successful, and if not, we will retry after 
@@ -591,6 +621,43 @@ void ircomm_tty_watchdog_timer_expired(void *data)
        ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
 }
 
+
+/*
+ * Function ircomm_tty_do_event (self, event, skb)
+ *
+ *    Process event
+ *
+ */
+int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
+                       struct sk_buff *skb, struct ircomm_tty_info *info) 
+{
+       ASSERT(self != NULL, return -1;);
+       ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+       IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+                  ircomm_tty_state[self->state], ircomm_tty_event[event]);
+       
+       return (*state[self->state])(self, event, skb, info);
+}
+
+/*
+ * Function ircomm_tty_next_state (self, state)
+ *
+ *    Switch state
+ *
+ */
+static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
+{
+       /*
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+       IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ , 
+                  ircomm_tty_state[self->state], self->service_type);
+       */
+       self->state = state;
+}
+
 /*
  * Function ircomm_tty_state_idle (self, event, skb, info)
  *
@@ -700,6 +767,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
                break;
        case IRCOMM_TTY_CONNECT_INDICATION:
                del_timer(&self->watchdog_timer);
+               ircomm_tty_ias_unregister(self);
 
                /* Accept connection */
                ircomm_connect_response(self->ircomm, NULL);
@@ -765,6 +833,7 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
                break;
        case IRCOMM_TTY_CONNECT_INDICATION:
                del_timer(&self->watchdog_timer);
+               ircomm_tty_ias_unregister(self);
 
                /* Accept connection */
                ircomm_connect_response(self->ircomm, NULL);
@@ -813,6 +882,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
                break;
        case IRCOMM_TTY_CONNECT_INDICATION:
                del_timer(&self->watchdog_timer);
+               ircomm_tty_ias_unregister(self);
 
                /* Accept connection */
                ircomm_connect_response(self->ircomm, NULL);
@@ -848,7 +918,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
        switch (event) {
        case IRCOMM_TTY_CONNECT_CONFIRM:
                del_timer(&self->watchdog_timer);
-               ircomm_tty_next_state(self, IRCOMM_TTY_READY);
+               ircomm_tty_ias_unregister(self);
                
                /* 
                 * Send initial parameters. This will also send out queued
@@ -856,9 +926,11 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
                 */
                ircomm_tty_send_initial_parameters(self);
                ircomm_tty_link_established(self);
+               ircomm_tty_next_state(self, IRCOMM_TTY_READY);
                break;
        case IRCOMM_TTY_CONNECT_INDICATION:
                del_timer(&self->watchdog_timer);
+               ircomm_tty_ias_unregister(self);
                
                /* Accept connection */
                ircomm_connect_response(self->ircomm, NULL);
@@ -903,6 +975,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
                ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
                break;
        case IRCOMM_TTY_DISCONNECT_INDICATION:
+               ircomm_tty_ias_register(self);
                ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
                ircomm_tty_start_watchdog_timer(self, 3*HZ);
 
@@ -924,38 +997,3 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
        return ret;
 }
 
-/*
- * Function ircomm_tty_do_event (self, event, skb)
- *
- *    Process event
- *
- */
-int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
-                       struct sk_buff *skb, struct ircomm_tty_info *info) 
-{
-       ASSERT(self != NULL, return -1;);
-       ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
-       IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
-                  ircomm_tty_state[self->state], ircomm_tty_event[event]);
-       
-       return (*state[self->state])(self, event, skb, info);
-}
-
-/*
- * Function ircomm_tty_next_state (self, state)
- *
- *    Switch state
- *
- */
-void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
-{
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
-       self->state = state;
-       
-       IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ , 
-                  ircomm_tty_state[self->state], self->service_type);
-}
-
index 058bf54..bc8d74d 100644 (file)
@@ -159,11 +159,14 @@ int irias_delete_object(struct ias_object *obj)
        ASSERT(obj != NULL, return -1;);
        ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
 
+       /* Remove from list */
        node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj);
        if (!node)
-               return 0; /* Already removed */
+               IRDA_DEBUG( 0, "%s(), object already removed!\n",
+                           __FUNCTION__);
 
-       __irias_delete_object(node);
+       /* Destroy */
+       __irias_delete_object(obj);
 
        return 0;
 }
@@ -176,7 +179,8 @@ EXPORT_SYMBOL(irias_delete_object);
  *    the object, remove the object as well.
  *
  */
-int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib)
+int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib,
+                       int cleanobject)
 {
        struct ias_attrib *node;
 
@@ -192,9 +196,13 @@ int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib)
        /* Deallocate attribute */
        __irias_delete_attrib(node);
 
-       /* Check if object has still some attributes */
+       /* Check if object has still some attributes, destroy it if none.
+        * At first glance, this look dangerous, as the kernel reference
+        * various IAS objects. However, we only use this function on
+        * user attributes, not kernel attributes, so there is no risk
+        * of deleting a kernel object this way. Jean II */
        node = (struct ias_attrib *) hashbin_get_first(obj->attribs);
-       if (!node)
+       if (cleanobject && !node)
                irias_delete_object(obj);
 
        return 0;
index b849ecd..90c8221 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
+#include <linux/bitops.h>
 #include <net/arp.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/byteorder.h>
 
 #include <net/irda/irda.h>
@@ -234,7 +234,7 @@ static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
        ASSERT(tsap == self->client.tsap_ctrl, return;);
 
                /* Remove frames queued on the control channel */
-       while ((skb = skb_dequeue(&self->client.txq))) {
+       while ((skb = skb_dequeue(&self->client.txq)) != NULL) {
                dev_kfree_skb(skb);
        }
        self->client.tx_busy = FALSE;
index e659907..032ab40 100644 (file)
@@ -37,9 +37,9 @@
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/moduleparam.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/byteorder.h>
 
 #include <net/irda/irda.h>
index abf11e4..2793c54 100644 (file)
@@ -33,9 +33,9 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/random.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/byteorder.h>
 
 #include <net/irda/irda.h>
index a81e0af..7ecc67c 100644 (file)
@@ -62,7 +62,7 @@ extern int  irlap_driver_rcv(struct sk_buff *, struct net_device *,
 #ifdef CONFIG_IRDA_DEBUG
 unsigned int irda_debug = IRDA_DEBUG_LEVEL;
 module_param_named(debug, irda_debug, uint, 0);
-MODULE_PARM_DESC(irda_debug, "IRDA debugging level");
+MODULE_PARM_DESC(debug, "IRDA debugging level");
 EXPORT_SYMBOL(irda_debug);
 #endif
 
index b81d56c..24748b6 100644 (file)
@@ -1111,3 +1111,4 @@ module_exit(irnet_cleanup);
 MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
 MODULE_DESCRIPTION("IrNET : Synchronous PPP over IrDA"); 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV(10, 187);
index b02d2db..d37dd25 100644 (file)
@@ -211,17 +211,6 @@ static int msb_index (__u16 word)
        return index;
 }
 
-static inline __u32 byte_value(__u8 byte, __u32 *array) 
-{
-       int index;
-
-       ASSERT(array != NULL, return -1;);
-
-       index = msb_index(byte);
-
-       return index_value(index, array);
-}
-
 /*
  * Function value_lower_bits (value, array)
  *
index f05b942..0b28118 100644 (file)
@@ -34,6 +34,8 @@
 #include <net/irda/irlap.h>
 #include <net/irda/irlmp.h>
 
+extern int  sysctl_slot_timeout;
+
 static void irlap_slot_timer_expired(void* data);
 static void irlap_query_timer_expired(void* data);
 static void irlap_final_timer_expired(void* data);
@@ -47,8 +49,25 @@ void irlap_start_slot_timer(struct irlap_cb *self, int timeout)
                         irlap_slot_timer_expired);
 }
 
-void irlap_start_query_timer(struct irlap_cb *self, int timeout)
+void irlap_start_query_timer(struct irlap_cb *self, int S, int s)
 {
+       int timeout;
+
+       /* Calculate when the peer discovery should end. Normally, we
+        * get the end-of-discovery frame, so this is just in case
+        * we miss it.
+        * Basically, we multiply the number of remaining slots by our
+        * slot time, plus add some extra time to properly receive the last
+        * discovery packet (which is longer due to extra discovery info),
+        * to avoid messing with for incomming connections requests and
+        * to accomodate devices that perform discovery slower than us.
+        * Jean II */
+       timeout = ((sysctl_slot_timeout * HZ / 1000) * (S - s)
+                  + XIDEXTRA_TIMEOUT + SMALLBUSY_TIMEOUT);
+
+       /* Set or re-set the timer. We reset the timer for each received
+        * discovery query, which allow us to automatically adjust to
+        * the speed of the peer discovery (faster or slower). Jean II */
        irda_start_timer( &self->query_timer, timeout, (void *) self, 
                          irlap_query_timer_expired);
 }
index 72059f1..59f53de 100644 (file)
@@ -28,8 +28,8 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
index dac2e36..f667a29 100644 (file)
@@ -186,7 +186,7 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
                nr_node->which = 0;
                nr_node->count = 1;
                atomic_set(&nr_node->refcount, 1);
-               nr_node->node_lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&nr_node->node_lock);
 
                nr_node->routes[0].quality   = quality;
                nr_node->routes[0].obs_count = obs_count;
index b189f5a..a6de2b4 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -31,7 +31,8 @@
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <net/sock.h>
-#include <net/pkt_sched.h>
+#include <net/sch_generic.h>
+#include <net/act_api.h>
 
 #if 1 /* control */
 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
@@ -87,7 +88,7 @@ int tcf_unregister_action(struct tc_action_ops *act)
 }
 
 /* lookup by name */
-struct tc_action_ops *tc_lookup_action_n(char *kind)
+static struct tc_action_ops *tc_lookup_action_n(char *kind)
 {
 
        struct tc_action_ops *a = NULL;
@@ -110,7 +111,7 @@ struct tc_action_ops *tc_lookup_action_n(char *kind)
 }
 
 /* lookup by rtattr */
-struct tc_action_ops *tc_lookup_action(struct rtattr *kind)
+static struct tc_action_ops *tc_lookup_action(struct rtattr *kind)
 {
 
        struct tc_action_ops *a = NULL;
@@ -133,8 +134,9 @@ struct tc_action_ops *tc_lookup_action(struct rtattr *kind)
        return a;
 }
 
+#if 0
 /* lookup by id */
-struct tc_action_ops *tc_lookup_action_id(u32 type)
+static struct tc_action_ops *tc_lookup_action_id(u32 type)
 {
        struct tc_action_ops *a = NULL;
 
@@ -154,6 +156,7 @@ struct tc_action_ops *tc_lookup_action_id(u32 type)
 
        return a;
 }
+#endif
 
 int tcf_action_exec(struct sk_buff *skb,struct tc_action *act, struct tcf_result *res)
 {
@@ -415,14 +418,45 @@ bad_ret:
 
 int tcf_action_copy_stats (struct sk_buff *skb,struct tc_action *a)
 {
+       int err;
+       struct gnet_dump d;
+       struct tcf_act_hdr *h = a->priv;
+       
 #ifdef CONFIG_KMOD
        /* place holder */
 #endif
 
-       if (NULL == a->ops || NULL == a->ops->get_stats)
-               return 1;
+       if (NULL == h)
+               goto errout;
+
+       if (a->type == TCA_OLD_COMPAT)
+               err = gnet_stats_start_copy_compat(skb, TCA_ACT_STATS,
+                       TCA_STATS, TCA_XSTATS, h->stats_lock, &d);
+       else
+               err = gnet_stats_start_copy(skb, TCA_ACT_STATS,
+                       h->stats_lock, &d);
 
-       return a->ops->get_stats(skb,a);
+       if (err < 0)
+               goto errout;
+
+       if (NULL != a->ops && NULL != a->ops->get_stats)
+               if (a->ops->get_stats(skb, a) < 0)
+                       goto errout;
+
+       if (gnet_stats_copy_basic(&d, &h->bstats) < 0 ||
+#ifdef CONFIG_NET_ESTIMATOR
+           gnet_stats_copy_rate_est(&d, &h->rate_est) < 0 ||
+#endif
+           gnet_stats_copy_queue(&d, &h->qstats) < 0)
+               goto errout;
+
+       if (gnet_stats_finish_copy(&d) < 0)
+               goto errout;
+
+       return 0;
+
+errout:
+       return -1;
 }
 
 
@@ -480,7 +514,7 @@ static int act_get_notify(u32 pid, struct nlmsghdr *n,
        return err;
 }
 
-int tcf_action_get_1(struct rtattr *rta, struct tc_action *a, struct nlmsghdr *n, u32 pid)
+static int tcf_action_get_1(struct rtattr *rta, struct tc_action *a, struct nlmsghdr *n, u32 pid)
 {
        struct tc_action_ops *a_o;
        char act_name[4 + IFNAMSIZ + 1];
@@ -547,7 +581,7 @@ err_out:
        return err;
 }
 
-void cleanup_a (struct tc_action *act) 
+static void cleanup_a (struct tc_action *act) 
 {
        struct tc_action *a;
 
@@ -563,7 +597,7 @@ void cleanup_a (struct tc_action *act)
        }
 }
 
-struct tc_action_ops *get_ao(struct rtattr *kind, struct tc_action *a)
+static struct tc_action_ops *get_ao(struct rtattr *kind, struct tc_action *a)
 {
        char act_name[4 + IFNAMSIZ + 1];
        struct tc_action_ops *a_o = NULL;
@@ -598,7 +632,7 @@ struct tc_action_ops *get_ao(struct rtattr *kind, struct tc_action *a)
        return a_o;
 }
 
-struct tc_action *create_a(int i)
+static struct tc_action *create_a(int i)
 {
        struct tc_action *act = NULL;
 
@@ -615,7 +649,7 @@ struct tc_action *create_a(int i)
        return act;
 }
 
-int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid)
+static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid)
 {
        struct sk_buff *skb;
        unsigned char *b;
@@ -685,7 +719,7 @@ err_out:
        return err;
 }
 
-int tca_action_gd(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int event )
+static int tca_action_gd(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int event )
 {
 
        int s = 0;
@@ -769,7 +803,7 @@ nlmsg_failure:
 }
 
 
-int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, unsigned flags) 
+static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, unsigned flags) 
 {
        struct tcamsg *t;
        struct nlmsghdr  *nlh;
@@ -816,7 +850,7 @@ nlmsg_failure:
 }
 
        
-int tcf_action_add(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int ovr ) 
+static int tcf_action_add(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int ovr ) 
 {
        int ret = 0;
        struct tc_action *act = NULL;
@@ -899,7 +933,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
        return ret;
 }
 
-char *
+static char *
 find_dump_kind(struct nlmsghdr *n)
 {
        struct rtattr *tb1, *tb2[TCA_ACT_MAX+1];
index 05a937b..ad26137 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -32,7 +32,8 @@
 #include <net/route.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/pkt_sched.h>
+#include <net/act_api.h>
+#include <net/pkt_cls.h>
 
 #define RSVP_DST_LEN   1
 #define RSVP_ID                "rsvp"
index 85ed7b4..fde51f7 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -33,7 +33,8 @@
 #include <net/route.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/pkt_sched.h>
+#include <net/act_api.h>
+#include <net/pkt_cls.h>
 
 #define RSVP_DST_LEN   4
 #define RSVP_ID                "rsvp6"
index 5607f5e..1cf0b17 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -53,16 +53,16 @@ static rwlock_t gact_lock = RW_LOCK_UNLOCKED;
 
 #ifdef CONFIG_GACT_PROB
 typedef int (*g_rand)(struct tcf_gact *p);
-int
+static int
 gact_net_rand(struct tcf_gact *p) {
        if (net_random()%p->pval)
                return p->action;
        return p->paction;
 }
 
-int
+static int
 gact_determ(struct tcf_gact *p) {
-       if (p->stats.packets%p->pval)
+       if (p->bstats.packets%p->pval)
                return p->action;
        return p->paction;
 }
@@ -71,7 +71,7 @@ gact_determ(struct tcf_gact *p) {
 g_rand gact_rand[MAX_RAND]= { NULL,gact_net_rand, gact_determ};
 
 #endif
-int
+static int
 tcf_gact_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,int ovr,int bind)
 {
        struct rtattr *tb[TCA_GACT_MAX];
@@ -129,7 +129,7 @@ override:
        return ret;
 }
 
-int
+static int
 tcf_gact_cleanup(struct tc_action *a, int bind)
 {
        struct tcf_gact *p;
@@ -139,7 +139,7 @@ tcf_gact_cleanup(struct tc_action *a, int bind)
        return 0;
 }
 
-int
+static int
 tcf_gact(struct sk_buff **pskb, struct tc_action *a)
 {
        struct tcf_gact *p;
@@ -163,17 +163,17 @@ tcf_gact(struct sk_buff **pskb, struct tc_action *a)
 #else
        action = p->action;
 #endif
-       p->stats.bytes += skb->len;
-       p->stats.packets++;
+       p->bstats.bytes += skb->len;
+       p->bstats.packets++;
        if (TC_ACT_SHOT == action)
-               p->stats.drops++;
+               p->qstats.drops++;
        p->tm.lastuse = jiffies;
        spin_unlock(&p->lock);
 
        return action;
 }
 
-int
+static int
 tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
 {
        unsigned char *b = skb->tail;
@@ -203,9 +203,9 @@ tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
                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;
+       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_GACT_TM, sizeof (t), &t);
        return skb->len;
 
@@ -214,25 +214,13 @@ tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
        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 = {
+static 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,
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);
+
index 28b61f0..96203ed 100644 (file)
@@ -241,11 +241,11 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch)
 #endif
 
            ((ret = p->q->enqueue(skb,p->q)) != 0)) {
-               sch->stats.drops++;
+               sch->qstats.drops++;
                return ret;
        }
-       sch->stats.bytes += skb->len;
-       sch->stats.packets++;
+       sch->bstats.bytes += skb->len;
+       sch->bstats.packets++;
        sch->q.qlen++;
        return ret;
 }
@@ -297,9 +297,10 @@ static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch)
        D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p);
         if ((ret = p->q->ops->requeue(skb, p->q)) == 0) {
                sch->q.qlen++;
+               sch->qstats.requeues++;
                return 0;
        }
-       sch->stats.drops++;
+       sch->qstats.drops++;
        return ret;
 }
 
index b089924..4888305 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -47,14 +47,14 @@ bfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 {
        struct fifo_sched_data *q = qdisc_priv(sch);
 
-       if (sch->stats.backlog + skb->len <= q->limit) {
+       if (sch->qstats.backlog + skb->len <= q->limit) {
                __skb_queue_tail(&sch->q, skb);
-               sch->stats.backlog += skb->len;
-               sch->stats.bytes += skb->len;
-               sch->stats.packets++;
+               sch->qstats.backlog += skb->len;
+               sch->bstats.bytes += skb->len;
+               sch->bstats.packets++;
                return 0;
        }
-       sch->stats.drops++;
+       sch->qstats.drops++;
 #ifdef CONFIG_NET_CLS_POLICE
        if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch))
 #endif
@@ -66,7 +66,8 @@ static int
 bfifo_requeue(struct sk_buff *skb, struct Qdisc* sch)
 {
        __skb_queue_head(&sch->q, skb);
-       sch->stats.backlog += skb->len;
+       sch->qstats.backlog += skb->len;
+       sch->qstats.requeues++;
        return 0;
 }
 
@@ -77,7 +78,7 @@ bfifo_dequeue(struct Qdisc* sch)
 
        skb = __skb_dequeue(&sch->q);
        if (skb)
-               sch->stats.backlog -= skb->len;
+               sch->qstats.backlog -= skb->len;
        return skb;
 }
 
@@ -89,7 +90,7 @@ fifo_drop(struct Qdisc* sch)
        skb = __skb_dequeue_tail(&sch->q);
        if (skb) {
                unsigned int len = skb->len;
-               sch->stats.backlog -= len;
+               sch->qstats.backlog -= len;
                kfree_skb(skb);
                return len;
        }
@@ -100,7 +101,7 @@ static void
 fifo_reset(struct Qdisc* sch)
 {
        skb_queue_purge(&sch->q);
-       sch->stats.backlog = 0;
+       sch->qstats.backlog = 0;
 }
 
 static int
@@ -110,11 +111,11 @@ pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
        if (sch->q.qlen < q->limit) {
                __skb_queue_tail(&sch->q, skb);
-               sch->stats.bytes += skb->len;
-               sch->stats.packets++;
+               sch->bstats.bytes += skb->len;
+               sch->bstats.packets++;
                return 0;
        }
-       sch->stats.drops++;
+       sch->qstats.drops++;
 #ifdef CONFIG_NET_CLS_POLICE
        if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch))
 #endif
@@ -126,6 +127,7 @@ static int
 pfifo_requeue(struct sk_buff *skb, struct Qdisc* sch)
 {
        __skb_queue_head(&sch->q, skb);
+       sch->qstats.requeues++;
        return 0;
 }
 
index d29df1c..1e2deaf 100644 (file)
@@ -15,7 +15,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -142,23 +142,27 @@ static int delay_skb(struct Qdisc *sch, struct sk_buff *skb)
 {
        struct netem_sched_data *q = qdisc_priv(sch);
        struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb;
+       psched_tdiff_t td;
        psched_time_t now;
        
        PSCHED_GET_TIME(now);
-       PSCHED_TADD2(now, tabledist(q->latency, q->jitter, 
-                                   &q->delay_cor, q->delay_dist),
-                    cb->time_to_send);
+       td = tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist);
+       PSCHED_TADD2(now, td, cb->time_to_send);
        
        /* Always queue at tail to keep packets in order */
        if (likely(q->delayed.qlen < q->limit)) {
                __skb_queue_tail(&q->delayed, skb);
-               sch->q.qlen++;
-               sch->stats.bytes += skb->len;
-               sch->stats.packets++;
+               sch->bstats.bytes += skb->len;
+               sch->bstats.packets++;
+
+               if (!timer_pending(&q->timer)) {
+                       q->timer.expires = jiffies + PSCHED_US2JIFFIE(td);
+                       add_timer(&q->timer);
+               }
                return NET_XMIT_SUCCESS;
        }
 
-       sch->stats.drops++;
+       sch->qstats.drops++;
        kfree_skb(skb);
        return NET_XMIT_DROP;
 }
@@ -172,7 +176,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        /* Random packet drop 0 => none, ~0 => all */
        if (q->loss && q->loss >= get_crandom(&q->loss_cor)) {
                pr_debug("netem_enqueue: random loss\n");
-               sch->stats.drops++;
+               sch->qstats.drops++;
                return 0;       /* lie about loss so TCP doesn't know */
        }
 
@@ -195,8 +199,12 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
                ++q->counter;
                ret = q->qdisc->enqueue(skb, q->qdisc);
-               if (ret)
-                       sch->stats.drops++;
+               if (likely(ret == NET_XMIT_SUCCESS)) {
+                       sch->q.qlen++;
+                       sch->bstats.bytes += skb->len;
+                       sch->bstats.packets++;
+               } else
+                       sch->qstats.drops++;
                return ret;
        }
        
@@ -211,8 +219,10 @@ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
        struct netem_sched_data *q = qdisc_priv(sch);
        int ret;
 
-       if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0)
+       if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) {
                sch->q.qlen++;
+               sch->qstats.requeues++;
+       }
 
        return ret;
 }
@@ -224,7 +234,7 @@ static unsigned int netem_drop(struct Qdisc* sch)
 
        if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) {
                sch->q.qlen--;
-               sch->stats.drops++;
+               sch->qstats.drops++;
        }
        return len;
 }
@@ -237,15 +247,32 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
 {
        struct netem_sched_data *q = qdisc_priv(sch);
        struct sk_buff *skb;
+
+       skb = q->qdisc->dequeue(q->qdisc);
+       if (skb) 
+               sch->q.qlen--;
+       return skb;
+}
+
+static void netem_watchdog(unsigned long arg)
+{
+       struct Qdisc *sch = (struct Qdisc *)arg;
+       struct netem_sched_data *q = qdisc_priv(sch);
+       struct net_device *dev = sch->dev;
+       struct sk_buff *skb;
        psched_time_t now;
 
+       pr_debug("netem_watchdog: fired @%lu\n", jiffies);
+
+       spin_lock_bh(&dev->queue_lock);
        PSCHED_GET_TIME(now);
+
        while ((skb = skb_peek(&q->delayed)) != NULL) {
                const struct netem_skb_cb *cb
                        = (const struct netem_skb_cb *)skb->cb;
                long delay 
                        = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now));
-               pr_debug("netem_dequeue: delay queue %p@%lu %ld\n",
+               pr_debug("netem_watchdog: skb %p@%lu %ld\n",
                         skb, jiffies, delay);
 
                /* if more time remaining? */
@@ -256,21 +283,12 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
                __skb_unlink(skb, &q->delayed);
 
                if (q->qdisc->enqueue(skb, q->qdisc))
-                       sch->stats.drops++;
+                       sch->qstats.drops++;
+               else
+                       sch->q.qlen++;
        }
-
-       skb = q->qdisc->dequeue(q->qdisc);
-       if (skb) 
-               sch->q.qlen--;
-       return skb;
-}
-
-static void netem_watchdog(unsigned long arg)
-{
-       struct Qdisc *sch = (struct Qdisc *)arg;
-
-       pr_debug("netem_watchdog: fired @%lu\n", jiffies);
-       netif_schedule(sch->dev);
+       qdisc_run(dev);
+       spin_unlock_bh(&dev->queue_lock);
 }
 
 static void netem_reset(struct Qdisc *sch)
index ac668b0..8734bb7 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
@@ -227,7 +227,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
                kfree_skb(skb);
                sfq_dec(q, x);
                sch->q.qlen--;
-               sch->stats.drops++;
+               sch->qstats.drops++;
                return len;
        }
 
@@ -243,7 +243,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
                sfq_dec(q, d);
                sch->q.qlen--;
                q->ht[q->hash[d]] = SFQ_DEPTH;
-               sch->stats.drops++;
+               sch->qstats.drops++;
                return len;
        }
 
@@ -276,8 +276,8 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
                }
        }
        if (++sch->q.qlen < q->limit-1) {
-               sch->stats.bytes += skb->len;
-               sch->stats.packets++;
+               sch->bstats.bytes += skb->len;
+               sch->bstats.packets++;
                return 0;
        }
 
@@ -310,10 +310,12 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
                        q->tail = x;
                }
        }
-       if (++sch->q.qlen < q->limit - 1)
+       if (++sch->q.qlen < q->limit - 1) {
+               sch->qstats.requeues++;
                return 0;
+       }
 
-       sch->stats.drops++;
+       sch->qstats.drops++;
        sfq_drop(sch);
        return NET_XMIT_CN;
 }
index dd16909..6cf0342 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -96,14 +96,14 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
        __skb_queue_tail(&q->q, skb);
        if (q->q.qlen <= dev->tx_queue_len) {
-               sch->stats.bytes += skb->len;
-               sch->stats.packets++;
+               sch->bstats.bytes += skb->len;
+               sch->bstats.packets++;
                return 0;
        }
 
        __skb_unlink(skb, &q->q);
        kfree_skb(skb);
-       sch->stats.drops++;
+       sch->qstats.drops++;
        return NET_XMIT_DROP;
 }
 
@@ -113,6 +113,7 @@ teql_requeue(struct sk_buff *skb, struct Qdisc* sch)
        struct teql_sched_data *q = qdisc_priv(sch);
 
        __skb_queue_head(&q->q, skb);
+       sch->qstats.requeues++;
        return 0;
 }
 
index 198ab76..c4a2370 100644 (file)
@@ -421,15 +421,15 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
 {
        switch (reason) {
        case SCTP_LOWER_CWND_T3_RTX:
-               /* RFC 2960 Section 7.2.3, sctpimpguide-05 Section 2.9.2
+               /* RFC 2960 Section 7.2.3, sctpimpguide
                 * When the T3-rtx timer expires on an address, SCTP should
                 * perform slow start by:
-                *      ssthresh = max(cwnd/2, 2*MTU)
+                *      ssthresh = max(cwnd/2, 4*MTU)
                 *      cwnd = 1*MTU
                 *      partial_bytes_acked = 0
                 */
                transport->ssthresh = max(transport->cwnd/2,
-                                         2*transport->asoc->pmtu);
+                                         4*transport->asoc->pmtu);
                transport->cwnd = transport->asoc->pmtu;
                break;
 
@@ -439,15 +439,15 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                 * were last sent, according to the formula described in
                 * Section 7.2.3.
                 *
-                * RFC 2960 7.2.3, sctpimpguide-05 2.9.2 Upon detection of
-                * packet losses from SACK (see Section 7.2.4), An endpoint
+                * RFC 2960 7.2.3, sctpimpguide Upon detection of packet
+                * losses from SACK (see Section 7.2.4), An endpoint
                 * should do the following:
-                *      ssthresh = max(cwnd/2, 2*MTU)
+                *      ssthresh = max(cwnd/2, 4*MTU)
                 *      cwnd = ssthresh
                 *      partial_bytes_acked = 0
                 */
                transport->ssthresh = max(transport->cwnd/2,
-                                         2*transport->asoc->pmtu);
+                                         4*transport->asoc->pmtu);
                transport->cwnd = transport->ssthresh;
                break;
 
@@ -467,23 +467,24 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                if ((jiffies - transport->last_time_ecne_reduced) >
                    transport->rtt) {
                        transport->ssthresh = max(transport->cwnd/2,
-                                                 2*transport->asoc->pmtu);
+                                                 4*transport->asoc->pmtu);
                        transport->cwnd = transport->ssthresh;
                        transport->last_time_ecne_reduced = jiffies;
                }
                break;
 
        case SCTP_LOWER_CWND_INACTIVE:
-               /* RFC 2960 Section 7.2.1, sctpimpguide-05 Section 2.14.2
-                * When the association does not transmit data on a given
-                * transport address within an RTO, the cwnd of the transport
-                * address should be adjusted to 2*MTU.
+               /* RFC 2960 Section 7.2.1, sctpimpguide
+                * When the endpoint does not transmit data on a given
+                * transport address, the cwnd of the transport address
+                * should be adjusted to max(cwnd/2, 4*MTU) per RTO.
                 * NOTE: Although the draft recommends that this check needs
                 * to be done every RTO interval, we do it every hearbeat
                 * interval.
                 */
                if ((jiffies - transport->last_time_used) > transport->rto)
-                       transport->cwnd = 2*transport->asoc->pmtu;
+                       transport->cwnd = max(transport->cwnd/2,
+                                                4*transport->asoc->pmtu);
                break;
        };
 
index f58aa65..99af842 100644 (file)
@@ -92,7 +92,9 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
 /*
        x25_transmit_clear_request(nb, lci, 0x0D);
 */
-       printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype);
+
+       if (frametype != X25_CLEAR_CONFIRMATION)
+               printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype);
 
        return 0;
 }
index ef3140d..64fff05 100644 (file)
@@ -32,10 +32,11 @@ static __inline__ struct x25_route *x25_get_route_idx(loff_t pos)
 
        list_for_each(route_entry, &x25_route_list) {
                rt = list_entry(route_entry, struct x25_route, node);
-               if (--pos)
-                       break;
+               if (!pos--)
+                       goto found;
        }
-
+       rt = NULL;
+found:
        return rt;
 }
 
index 58c7d26..58ca6a9 100644 (file)
@@ -1,10 +1,6 @@
 #
 # XFRM configuration
 #
-config XFRM
-       bool
-       depends on NET
-
 config XFRM_USER
        tristate "IPsec user configuration interface"
        depends on INET && XFRM
index 672b008..d2263a3 100644 (file)
@@ -10,7 +10,7 @@ __build:
 # Read .config if it exist, otherwise ignore
 -include .config
 
-include $(obj)/Makefile
+include $(if $(wildcard $(obj)/Kbuild), $(obj)/Kbuild, $(obj)/Makefile)
 
 include scripts/Makefile.lib
 
@@ -83,6 +83,7 @@ __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
 
 # Linus' kernel sanity checking tool
 ifneq ($(KBUILD_CHECKSRC),0)
+  CHECKFLAGS += -I$(shell $(CC) -print-file-name=include)
   ifeq ($(KBUILD_CHECKSRC),2)
     quiet_cmd_force_checksrc = CHECK   $<
           cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
index b02ab1f..ff3e87d 100644 (file)
@@ -7,7 +7,7 @@ src := $(obj)
 .PHONY: __clean
 __clean:
 
-include $(obj)/Makefile
+include $(if $(wildcard $(obj)/Kbuild), $(obj)/Kbuild, $(obj)/Makefile)
 
 # Figure out what we need to build from the various variables
 # ==========================================================================
index 3a7663b..6e75ced 100644 (file)
@@ -232,3 +232,30 @@ descend =$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build ob
 # Usage:
 # $(Q)$(MAKE) $(build)=dir
 build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
+
+# filechk is used to check if the content of a generated file is updated.
+# Sample usage:
+# define filechk_sample
+#      echo $KERNELRELEASE
+# endef
+# version.h : Makefile
+#      $(call filechk,sample)
+# The rule defined shall write to stdout the content of the new file.
+# The existing file will be compared with the new one.
+# - If no file exist it is created
+# - If the content differ the new file is used
+# - If they are equal no change, and no timestamp update
+
+define filechk
+       $(Q)set -e;                             \
+       echo '  CHK     $@';                    \
+       mkdir -p $(dir $@);                     \
+       $(filechk_$(1)) $(2) > $@.tmp;          \
+       if [ -r $@ ] && cmp -s $@ $@.tmp; then  \
+               rm -f $@.tmp;                   \
+       else                                    \
+               echo '  UPD     $@';            \
+               mv -f $@.tmp $@;                \
+       fi
+endef
+
index d28f883..8ca7ecd 100644 (file)
@@ -52,7 +52,7 @@ FILEONLY *internalfunctions;
 FILEONLY *externalfunctions;
 FILEONLY *symbolsonly;
 
-typedef void FILELINE(char * file, char * line);
+typedef void FILELINE(char * file, signed char * line);
 FILELINE * singlefunctions;
 FILELINE * entity_system;
 
@@ -79,6 +79,7 @@ void exec_kernel_doc(char **svec)
 {
        pid_t pid;
        int ret;
+       char real_filename[PATH_MAX + 1];
        /* Make sure output generated so far are flushed */
        fflush(stdout);
        switch(pid=fork()) {
@@ -86,8 +87,13 @@ void exec_kernel_doc(char **svec)
                        perror("fork");
                        exit(1);
                case  0:
-                       execvp(KERNELDOCPATH KERNELDOC, svec);
-                       perror("exec " KERNELDOCPATH KERNELDOC);
+                       memset(real_filename, 0, sizeof(real_filename));
+                       strncat(real_filename, getenv("SRCTREE"), PATH_MAX);
+                       strncat(real_filename, KERNELDOCPATH KERNELDOC,
+                                       PATH_MAX - strlen(real_filename));
+                       execvp(real_filename, svec);
+                       fprintf(stderr, "exec ");
+                       perror(real_filename);
                        exit(1);
                default:
                        waitpid(pid, &ret ,0);
@@ -142,9 +148,9 @@ struct symfile * filename_exist(char * filename)
  * Files are separated by tabs.
  */
 void adddep(char * file)                  { printf("\t%s", file); }
-void adddep2(char * file, char * line)     { line = line; adddep(file); }
+void adddep2(char * file, signed char * line)     { line = line; adddep(file); }
 void noaction(char * line)                { line = line; }
-void noaction2(char * file, char * line)   { file = file; line = line; }
+void noaction2(char * file, signed char * line)   { file = file; line = line; }
 
 /* Echo the line without further action */
 void printline(char * line)               { printf("%s", line); }
@@ -160,16 +166,21 @@ void find_export_symbols(char * filename)
        struct symfile *sym;
        char line[MAXLINESZ];
        if (filename_exist(filename) == NULL) {
+               char real_filename[PATH_MAX + 1];
+               memset(real_filename, 0, sizeof(real_filename));
+               strncat(real_filename, getenv("SRCTREE"), PATH_MAX);
+               strncat(real_filename, filename,
+                               PATH_MAX - strlen(real_filename));
                sym = add_new_file(filename);
-               fp = fopen(filename, "r");
+               fp = fopen(real_filename, "r");
                if (fp == NULL)
                {
                        fprintf(stderr, "docproc: ");
-                       perror(filename);
+                       perror(real_filename);
                }
                while(fgets(line, MAXLINESZ, fp)) {
-                       char *p;
-                       char *e;
+                       signed char *p;
+                       signed char *e;
                        if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) ||
                             ((p = strstr(line, "EXPORT_SYMBOL")) != 0)) {
                                /* Skip EXPORT_SYMBOL{_GPL} */
@@ -242,7 +253,7 @@ void extfunc(char * filename) { docfunctions(filename, FUNCTION);   }
  * Call kernel-doc with the following parameters:
  * kernel-doc -docbook -function function1 [-function function2]
  */
-void singfunc(char * filename, char * line)
+void singfunc(char * filename, signed char * line)
 {
        char *vec[200]; /* Enough for specific functions */
         int i, idx = 0;
@@ -279,7 +290,7 @@ void singfunc(char * filename, char * line)
 void parse_file(FILE *infile)
 {
        char line[MAXLINESZ];
-       char * s;
+       signed char * s;
        while(fgets(line, MAXLINESZ, infile)) {
                if (line[0] == '!') {
                        s = line + 2;
index 459c452..60fc4d8 100644 (file)
@@ -104,7 +104,7 @@ int main(int argc, const char * argv [])
     /* Read config lines. */
     while (fgets(line, buffer_size, fp_config))
     {
-       const char * str_config;
+       const signed char * str_config;
        int is_same;
        int itarget;
 
index 7d33f0a..dd2db95 100644 (file)
@@ -39,6 +39,9 @@ my (@stack, $re, $x, $xs);
        } elsif ($arch =~ /^i[3456]86$/) {
                #c0105234:       81 ec ac 05 00 00       sub    $0x5ac,%esp
                $re = qr/^.*[as][du][db]    \$(0x$x{1,8}),\%esp$/o;
+       } elsif ($arch eq 'x86_64') {
+               #    2f60:      48 81 ec e8 05 00 00    sub    $0x5e8,%rsp
+               $re = qr/^.*[as][du][db]    \$(0x$x{1,8}),\%rsp$/o;
        } elsif ($arch eq 'ia64') {
                #e0000000044011fc:       01 0f fc 8c     adds r12=-384,r12
                $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
index e0c6891..93dd23f 100644 (file)
@@ -33,7 +33,7 @@ void usage(char *argv0)
 
 int getunicode(char **p0)
 {
-  char *p = *p0;
+  unsigned char *p = *p0;
 
   while (*p == ' ' || *p == '\t')
     p++;
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
index 7b6285e..1e82ae3 100644 (file)
@@ -27,10 +27,10 @@ const char *conf_confnames[] = {
        NULL,
 };
 
-static char *conf_expand_value(const char *in)
+static char *conf_expand_value(const signed char *in)
 {
        struct symbol *sym;
-       const char *src;
+       const signed char *src;
        static char res_value[SYMBOL_MAXLENGTH];
        char *dst, name[SYMBOL_MAXLENGTH];
 
@@ -270,6 +270,8 @@ int conf_write(const char *name)
        int type, l;
        const char *str;
        time_t now;
+       int use_timestamp = 1;
+       char *env;
 
        dirname[0] = 0;
        if (name && name[0]) {
@@ -293,7 +295,7 @@ int conf_write(const char *name)
        } else
                basename = conf_def_filename;
 
-       sprintf(newname, "%s.tmpconfig.%d", dirname, getpid());
+       sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
        out = fopen(newname, "w");
        if (!out)
                return 1;
@@ -306,22 +308,28 @@ int conf_write(const char *name)
        sym = sym_lookup("KERNELRELEASE", 0);
        sym_calc_value(sym);
        time(&now);
+       env = getenv("KCONFIG_NOTIMESTAMP");
+       if (env && *env)
+               use_timestamp = 0;
+
        fprintf(out, "#\n"
                     "# Automatically generated make config: don't edit\n"
                     "# Linux kernel version: %s\n"
-                    "%s"
+                    "%s%s"
                     "#\n",
                     sym_get_string_value(sym),
-                    ctime(&now));
+                    use_timestamp ? "# " : "",
+                    use_timestamp ? ctime(&now) : "");
        if (out_h)
                fprintf(out_h, "/*\n"
                               " * Automatically generated C config: don't edit\n"
                               " * Linux kernel version: %s\n"
-                              " * %s"
+                              "%s%s"
                               " */\n"
                               "#define AUTOCONF_INCLUDED\n",
                               sym_get_string_value(sym),
-                              ctime(&now));
+                              use_timestamp ? " * " : "",
+                              use_timestamp ? ctime(&now) : "");
 
        if (!sym_change_count)
                sym_clear_all_valid();
index 16b48cf..dc35e07 100644 (file)
@@ -421,7 +421,7 @@ tristate sym_toggle_tristate_value(struct symbol *sym)
 
 bool sym_string_valid(struct symbol *sym, const char *str)
 {
-       char ch;
+       signed char ch;
 
        switch (sym->type) {
        case S_STRING:
index cdc4024..a45a13f 100644 (file)
@@ -1,5 +1,9 @@
 HOST_EXTRACFLAGS := -DLOCALE 
+ifeq ($(shell uname),SunOS)
+HOST_LOADLIBES   := -lcurses
+else
 HOST_LOADLIBES   := -lncurses
+endif
 
 ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
         HOST_EXTRACFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
index 0e30d00..c571548 100644 (file)
@@ -26,6 +26,9 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef __sun__
+#define CURS_MACROS
+#endif
 #include CURSES_LOC
 
 /*
index 2904d3b..a6430e0 100644 (file)
@@ -40,5 +40,5 @@
 # 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
+$NM -n $1 | grep -v '\( [aUw] \)\|\(__crc_\)\|\( \$[adt]\)' > $2
 
index f38c6d7..7c8f064 100644 (file)
 
 #include "modpost.h"
 
-/* We use the ELF typedefs, since we can't rely on stdint.h being present. */
-
+/* We use the ELF typedefs for kernel_ulong_t but bite the bullet and
+ * use either stdint.h or inttypes.h for the rest. */
 #if KERNEL_ELFCLASS == ELFCLASS32
-typedef Elf32_Addr     kernel_ulong_t;
+typedef Elf32_Addr     kernel_ulong_t;
+#else
+typedef Elf64_Addr     kernel_ulong_t;
+#endif
+#ifdef __sun__
+#include <inttypes.h>
 #else
-typedef Elf64_Addr     kernel_ulong_t;
+#include <stdint.h>
 #endif
 
-typedef Elf32_Word     __u32;
-typedef Elf32_Half     __u16;
-typedef unsigned char  __u8;
+typedef uint32_t       __u32;
+typedef uint16_t       __u16;
+typedef unsigned char  __u8;
 
 /* Big exception to the "don't include kernel headers into userspace, which
  * even potentially has different endianness and word sizes, since 
index 2a174e5..347549c 100644 (file)
@@ -1,7 +1,7 @@
 /* Postprocess module symbol versions
  *
  * Copyright 2003       Kai Germaschewski
- *           2002-2003  Rusty Russell, IBM Corporation
+ * Copyright 2002-2004  Rusty Russell, IBM Corporation
  *
  * Based in part on module-init-tools/depmod.c,file2alias
  *
@@ -18,6 +18,8 @@
 int modversions = 0;
 /* Warn about undefined symbols? (do so if we have vmlinux) */
 int have_vmlinux = 0;
+/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
+static int all_versions = 0;
 
 void
 fatal(const char *fmt, ...)
@@ -102,6 +104,7 @@ struct symbol {
        struct module *module;
        unsigned int crc;
        int crc_valid;
+       unsigned int weak:1;
        char name[0];
 };
 
@@ -124,12 +127,13 @@ static inline unsigned int tdb_hash(const char *name)
  * the list of unresolved symbols per module */
 
 struct symbol *
-alloc_symbol(const char *name, struct symbol *next)
+alloc_symbol(const char *name, unsigned int weak, struct symbol *next)
 {
        struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
 
        memset(s, 0, sizeof(*s));
        strcpy(s->name, name);
+       s->weak = weak;
        s->next = next;
        return s;
 }
@@ -143,7 +147,7 @@ new_symbol(const char *name, struct module *module, unsigned int *crc)
        struct symbol *new;
 
        hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
-       new = symbolhash[hash] = alloc_symbol(name, symbolhash[hash]);
+       new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
        new->module = module;
        if (crc) {
                new->crc = *crc;
@@ -215,7 +219,7 @@ get_next_line(unsigned long *pos, void *file, unsigned long size)
        static char line[4096];
        int skip = 1;
        size_t len = 0;
-       char *p = (char *)file + *pos;
+       signed char *p = (signed char *)file + *pos;
        char *s = line;
 
        for (; *pos < size ; (*pos)++)
@@ -347,7 +351,8 @@ handle_modversions(struct module *mod, struct elf_info *info,
                break;
        case SHN_UNDEF:
                /* undefined symbol */
-               if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL)
+               if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
+                   ELF_ST_BIND(sym->st_info) != STB_WEAK)
                        break;
                /* ignore global offset table */
                if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
@@ -368,6 +373,7 @@ handle_modversions(struct module *mod, struct elf_info *info,
                           strlen(MODULE_SYMBOL_PREFIX)) == 0)
                        mod->unres = alloc_symbol(symname +
                                                  strlen(MODULE_SYMBOL_PREFIX),
+                                                 ELF_ST_BIND(sym->st_info) == STB_WEAK,
                                                  mod->unres);
                break;
        default:
@@ -397,10 +403,44 @@ is_vmlinux(const char *modname)
        return strcmp(myname, "vmlinux") == 0;
 }
 
+/* Parse tag=value strings from .modinfo section */
+static char *next_string(char *string, unsigned long *secsize)
+{
+       /* Skip non-zero chars */
+       while (string[0]) {
+               string++;
+               if ((*secsize)-- <= 1)
+                       return NULL;
+       }
+
+       /* Skip any zero padding. */
+       while (!string[0]) {
+               string++;
+               if ((*secsize)-- <= 1)
+                       return NULL;
+       }
+       return string;
+}
+
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+                        const char *tag)
+{
+       char *p;
+       unsigned int taglen = strlen(tag);
+       unsigned long size = modinfo_len;
+
+       for (p = modinfo; p; p = next_string(p, &size)) {
+               if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+                       return p + taglen + 1;
+       }
+       return NULL;
+}
+
 void
 read_symbols(char *modname)
 {
        const char *symname;
+       char *version;
        struct module *mod;
        struct elf_info info = { };
        Elf_Sym *sym;
@@ -424,8 +464,15 @@ read_symbols(char *modname)
                handle_modversions(mod, &info, sym, symname);
                handle_moddevtable(mod, &info, sym, symname);
        }
-       maybe_frob_version(modname, info.modinfo, info.modinfo_len,
-                          (void *)info.modinfo - (void *)info.hdr);
+
+       version = get_modinfo(info.modinfo, info.modinfo_len, "version");
+       if (version)
+               maybe_frob_rcs_version(modname, version, info.modinfo,
+                                      version - (char *)info.hdr);
+       if (version || (all_versions && !is_vmlinux(modname)))
+               get_src_version(modname, mod->srcversion,
+                               sizeof(mod->srcversion)-1);
+
        parse_elf_finish(&info);
 
        /* Our trick to get versioning for struct_module - it's
@@ -433,7 +480,7 @@ read_symbols(char *modname)
         * the automatic versioning doesn't pick it up, but it's really
         * important anyhow */
        if (modversions)
-               mod->unres = alloc_symbol("struct_module", mod->unres);
+               mod->unres = alloc_symbol("struct_module", 0, mod->unres);
 }
 
 #define SZ 500
@@ -505,7 +552,7 @@ add_versions(struct buffer *b, struct module *mod)
        for (s = mod->unres; s; s = s->next) {
                exp = find_symbol(s->name);
                if (!exp || exp->module == mod) {
-                       if (have_vmlinux)
+                       if (have_vmlinux && !s->weak)
                                fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
                                "undefined!\n", s->name, mod->name);
                        continue;
@@ -570,6 +617,16 @@ add_depends(struct buffer *b, struct module *mod, struct module *modules)
        buf_printf(b, "\";\n");
 }
 
+void
+add_srcversion(struct buffer *b, struct module *mod)
+{
+       if (mod->srcversion[0]) {
+               buf_printf(b, "\n");
+               buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
+                          mod->srcversion);
+       }
+}
+
 void
 write_if_changed(struct buffer *b, const char *fname)
 {
@@ -691,7 +748,7 @@ main(int argc, char **argv)
        char *dump_read = NULL, *dump_write = NULL;
        int opt;
 
-       while ((opt = getopt(argc, argv, "i:mo:")) != -1) {
+       while ((opt = getopt(argc, argv, "i:mo:a")) != -1) {
                switch(opt) {
                        case 'i':
                                dump_read = optarg;
@@ -702,6 +759,9 @@ main(int argc, char **argv)
                        case 'o':
                                dump_write = optarg;
                                break;
+                       case 'a':
+                               all_versions = 1;
+                               break;
                        default:
                                exit(1);
                }
@@ -724,6 +784,7 @@ main(int argc, char **argv)
                add_versions(&buf, mod);
                add_depends(&buf, mod, modules);
                add_moddevtable(&buf, mod);
+               add_srcversion(&buf, mod);
 
                sprintf(fname, "%s.mod.c", mod->name);
                write_if_changed(&buf, fname);
index 4871343..eb8815a 100644 (file)
@@ -77,6 +77,7 @@ struct module {
        int has_init;
        int has_cleanup;
        struct buffer dev_table_buf;
+       char         srcversion[25];
 };
 
 struct elf_info {
@@ -95,10 +96,11 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
 
 void add_moddevtable(struct buffer *buf, struct module *mod);
 
-void maybe_frob_version(const char *modfilename,
-                       void *modinfo,
-                       unsigned long modinfo_len,
-                       unsigned long modinfo_offset);
+void maybe_frob_rcs_version(const char *modfilename,
+                           char *version,
+                           void *modinfo,
+                           unsigned long modinfo_offset);
+void get_src_version(const char *modname, char sum[], unsigned sumlen);
 
 void *grab_file(const char *filename, unsigned long *size);
 char* get_next_line(unsigned long *pos, void *file, unsigned long size);
index 86ea6a3..6fe63c6 100644 (file)
@@ -9,39 +9,6 @@
 #include <string.h>
 #include "modpost.h"
 
-/* Parse tag=value strings from .modinfo section */
-static char *next_string(char *string, unsigned long *secsize)
-{
-       /* Skip non-zero chars */
-       while (string[0]) {
-               string++;
-               if ((*secsize)-- <= 1)
-                       return NULL;
-       }
-
-       /* Skip any zero padding. */
-       while (!string[0]) {
-               string++;
-               if ((*secsize)-- <= 1)
-                       return NULL;
-       }
-       return string;
-}
-
-static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
-                        const char *tag)
-{
-       char *p;
-       unsigned int taglen = strlen(tag);
-       unsigned long size = modinfo_len;
-
-       for (p = modinfo; p; p = next_string(p, &size)) {
-               if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
-                       return p + taglen + 1;
-       }
-       return NULL;
-}
-
 /*
  * Stolen form Cryptographic API.
  *
@@ -285,9 +252,9 @@ static int parse_comment(const char *file, unsigned long len)
 }
 
 /* FIXME: Handle .s files differently (eg. # starts comments) --RR */
-static int parse_file(const char *fname, struct md4_ctx *md)
+static int parse_file(const signed char *fname, struct md4_ctx *md)
 {
-       char *file;
+       signed char *file;
        unsigned long i, len;
 
        file = grab_file(fname, &len);
@@ -365,7 +332,7 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
           Sum all files in the same dir or subdirs.
        */
        while ((line = get_next_line(&pos, file, flen)) != NULL) {
-               char* p = line;
+               signed char* p = line;
                if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
                        check_files = 1;
                        continue;
@@ -408,15 +375,16 @@ out:
        return ret;
 }
 
-static int get_version(const char *modname, char sum[])
+/* Calc and record src checksum. */
+void get_src_version(const char *modname, char sum[], unsigned sumlen)
 {
        void *file;
        unsigned long len;
-       int ret = 0;
        struct md4_ctx md;
        char *sources, *end, *fname;
        const char *basename;
-       char filelist[sizeof(".tmp_versions/%s.mod") + strlen(modname)];
+       char filelist[strlen(getenv("MODVERDIR")) + strlen("/") +
+                     strlen(modname) - strlen(".o") + strlen(".mod") + 1 ];
 
        /* Source files for module are in .tmp_versions/modname.mod,
           after the first line. */
@@ -424,15 +392,14 @@ static int get_version(const char *modname, char sum[])
                basename = strrchr(modname, '/') + 1;
        else
                basename = modname;
-       sprintf(filelist, ".tmp_versions/%s", basename);
-       /* Truncate .o, add .mod */
-       strcpy(filelist + strlen(filelist)-2, ".mod");
+       sprintf(filelist, "%s/%.*s.mod", getenv("MODVERDIR"),
+               (int) strlen(basename) - 2, basename);
 
        file = grab_file(filelist, &len);
        if (!file) {
                fprintf(stderr, "Warning: could not find versions for %s\n",
                        filelist);
-               return 0;
+               return;
        }
 
        sources = strchr(file, '\n');
@@ -457,12 +424,9 @@ static int get_version(const char *modname, char sum[])
                        goto release;
        }
 
-       /* sum is of form \0<padding>. */
-       md4_final_ascii(&md, sum, 1 + strlen(sum+1));
-       ret = 1;
+       md4_final_ascii(&md, sum, sumlen);
 release:
        release_file(file, len);
-       return ret;
 }
 
 static void write_version(const char *filename, const char *sum,
@@ -492,12 +456,12 @@ out:
        close(fd);
 }
 
-void strip_rcs_crap(char *version)
+static int strip_rcs_crap(signed char *version)
 {
        unsigned int len, full_len;
 
        if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
-               return;
+               return 0;
 
        /* Space for version string follows. */
        full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
@@ -518,31 +482,15 @@ void strip_rcs_crap(char *version)
                len++;
        memmove(version + len, version + strlen(version),
                full_len - strlen(version));
+       return 1;
 }
 
-/* If the modinfo contains a "version" value, then set this. */
-void maybe_frob_version(const char *modfilename,
-                       void *modinfo,
-                       unsigned long modinfo_len,
-                       unsigned long modinfo_offset)
+/* Clean up RCS-style version numbers. */
+void maybe_frob_rcs_version(const char *modfilename,
+                           char *version,
+                           void *modinfo,
+                           unsigned long version_offset)
 {
-       char *version, *csum;
-
-       version = get_modinfo(modinfo, modinfo_len, "version");
-       if (!version)
-               return;
-
-       /* RCS $Revision gets stripped out. */
-       strip_rcs_crap(version);
-
-       /* Check against double sumversion */
-       if (strchr(version, ' '))
-               return;
-
-       /* Version contains embedded NUL: second half has space for checksum */
-       csum = version + strlen(version);
-       *(csum++) = ' ';
-       if (get_version(modfilename, csum))
-               write_version(modfilename, version,
-                             modinfo_offset + (version - (char *)modinfo));
+       if (strip_rcs_crap(version))
+               write_version(modfilename, version, version_offset);
 }
index ddde53b..576feff 100644 (file)
@@ -4,6 +4,35 @@
 
 menu "Security options"
 
+config KEYS
+       bool "Enable access key retention support"
+       help
+         This option provides support for retaining authentication tokens and
+         access keys in the kernel.
+
+         It also includes provision of methods by which such keys might be
+         associated with a process so that network filesystems, encryption
+         support and the like can find them.
+
+         Furthermore, a special type of key is available that acts as keyring:
+         a searchable sequence of keys. Each process is equipped with access
+         to five standard keyrings: UID-specific, GID-specific, session,
+         process and thread.
+
+         If you are unsure as to whether this is required, answer N.
+
+config KEYS_DEBUG_PROC_KEYS
+       bool "Enable the /proc/keys file by which all keys may be viewed"
+       depends on KEYS
+       help
+         This option turns on support for the /proc/keys file through which
+         all the keys on the system can be listed.
+
+         This option is a slight security risk in that it makes it possible
+         for anyone to see all the keys on the system. Normally the manager
+         pretends keys that are inaccessible to a process don't exist as far
+         as that process is concerned.
+
 config SECURITY
        bool "Enable different security models"
        help
@@ -44,6 +73,17 @@ config SECURITY_ROOTPLUG
          
          If you are unsure how to answer this question, answer N.
 
+config SECURITY_SECLVL
+       tristate "BSD Secure Levels"
+       depends on SECURITY
+       select CRYPTO_SHA1
+       help
+         Implements BSD Secure Levels as an LSM.  See
+         Documentation/seclvl.txt for instructions on how to use this
+         module.
+
+         If you are unsure how to answer this question, answer N.
+
 source security/selinux/Kconfig
 
 endmenu
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");
index 70a9fcf..e8e79c3 100644 (file)
 #include <linux/sched.h>
 #include <linux/security.h>
 
-#define SECURITY_SCAFFOLD_VERSION      "1.0.0"
+#define SECURITY_FRAMEWORK_VERSION     "1.0.0"
 
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
-extern void security_fixup_ops (struct security_operations *ops);
+extern void security_fixup_ops(struct security_operations *ops);
 
 struct security_operations *security_ops;      /* Initialized to NULL */
 
-static inline int verify (struct security_operations *ops)
+static inline int verify(struct security_operations *ops)
 {
        /* verify the security_operations structure exists */
-       if (!ops) {
-               printk (KERN_INFO "Passed a NULL security_operations "
-                       "pointer, %s failed.\n", __FUNCTION__);
+       if (!ops)
                return -EINVAL;
-       }
-       security_fixup_ops (ops);
+       security_fixup_ops(ops);
        return 0;
 }
 
@@ -43,24 +40,24 @@ static void __init do_security_initcalls(void)
        initcall_t *call;
        call = &__security_initcall_start;
        while (call < &__security_initcall_end) {
-               (*call)();
+               (*call) ();
                call++;
        }
 }
 
 /**
- * security_scaffolding_startup - initializes the security scaffolding framework
+ * security_init - initializes the security framework
  *
  * This should be called early in the kernel initialization sequence.
  */
-int __init security_scaffolding_startup (void)
+int __init security_init(void)
 {
-       printk (KERN_INFO "Security Scaffold v" SECURITY_SCAFFOLD_VERSION
-               " initialized\n");
+       printk(KERN_INFO "Security Framework v" SECURITY_FRAMEWORK_VERSION
+              " initialized\n");
 
-       if (verify (&dummy_security_ops)) {
-               printk (KERN_ERR "%s could not verify "
-                       "dummy_security_ops structure.\n", __FUNCTION__);
+       if (verify(&dummy_security_ops)) {
+               printk(KERN_ERR "%s could not verify "
+                      "dummy_security_ops structure.\n", __FUNCTION__);
                return -EIO;
        }
 
@@ -82,19 +79,16 @@ int __init security_scaffolding_startup (void)
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise 0 is returned on success.
  */
-int register_security (struct security_operations *ops)
+int register_security(struct security_operations *ops)
 {
-       if (verify (ops)) {
-               printk (KERN_INFO "%s could not verify "
-                       "security_operations structure.\n", __FUNCTION__);
+       if (verify(ops)) {
+               printk(KERN_DEBUG "%s could not verify "
+                      "security_operations structure.\n", __FUNCTION__);
                return -EINVAL;
        }
 
-       if (security_ops != &dummy_security_ops) {
-               printk (KERN_INFO "There is already a security "
-                       "framework initialized, %s failed.\n", __FUNCTION__);
-               return -EINVAL;
-       }
+       if (security_ops != &dummy_security_ops)
+               return -EAGAIN;
 
        security_ops = ops;
 
@@ -112,12 +106,12 @@ int register_security (struct security_operations *ops)
  * an error is returned.  Otherwise the default security options is set to the
  * the dummy_security_ops structure, and 0 is returned.
  */
-int unregister_security (struct security_operations *ops)
+int unregister_security(struct security_operations *ops)
 {
        if (ops != security_ops) {
-               printk (KERN_INFO "%s: trying to unregister "
-                       "a security_opts structure that is not "
-                       "registered, failing.\n", __FUNCTION__);
+               printk(KERN_INFO "%s: trying to unregister "
+                      "a security_opts structure that is not "
+                      "registered, failing.\n", __FUNCTION__);
                return -EINVAL;
        }
 
@@ -138,21 +132,21 @@ int unregister_security (struct security_operations *ops)
  * The return value depends on the currently loaded security module, with 0 as
  * success.
  */
-int mod_reg_security (const char *name, struct security_operations *ops)
+int mod_reg_security(const char *name, struct security_operations *ops)
 {
-       if (verify (ops)) {
-               printk (KERN_INFO "%s could not verify "
-                       "security operations.\n", __FUNCTION__);
+       if (verify(ops)) {
+               printk(KERN_INFO "%s could not verify "
+                      "security operations.\n", __FUNCTION__);
                return -EINVAL;
        }
 
        if (ops == security_ops) {
-               printk (KERN_INFO "%s security operations "
-                       "already registered.\n", __FUNCTION__);
+               printk(KERN_INFO "%s security operations "
+                      "already registered.\n", __FUNCTION__);
                return -EINVAL;
        }
 
-       return security_ops->register_security (name, ops);
+       return security_ops->register_security(name, ops);
 }
 
 /**
@@ -168,15 +162,15 @@ int mod_reg_security (const char *name, struct security_operations *ops)
  * The return value depends on the currently loaded security module, with 0 as
  * success.
  */
-int mod_unreg_security (const char *name, struct security_operations *ops)
+int mod_unreg_security(const char *name, struct security_operations *ops)
 {
        if (ops == security_ops) {
-               printk (KERN_INFO "%s invalid attempt to unregister "
-                       " primary security ops.\n", __FUNCTION__);
+               printk(KERN_INFO "%s invalid attempt to unregister "
+                      " primary security ops.\n", __FUNCTION__);
                return -EINVAL;
        }
 
-       return security_ops->unregister_security (name, ops);
+       return security_ops->unregister_security(name, ops);
 }
 
 /**
@@ -189,9 +183,9 @@ int mod_unreg_security (const char *name, struct security_operations *ops)
  * This allows the security module to implement the capable function call
  * however it chooses to.
  */
-int capable (int cap)
+int capable(int cap)
 {
-       if (security_ops->capable (current, cap)) {
+       if (security_ops->capable(current, cap)) {
                /* capability denied */
                return 0;
        }
index 56f5cc7..1e4511a 100644 (file)
@@ -70,7 +70,7 @@ source "sound/parisc/Kconfig"
 endmenu
 
 menu "Open Sound System"
-       depends on SOUND!=n && (BROKEN || !SPARC64)
+       depends on SOUND!=n && (BROKEN || !(SPARC32 || SPARC64))
 
 config SOUND_PRIME
        tristate "Open Sound System (DEPRECATED)"
index 1da2786..cdacf4d 100644 (file)
@@ -4,12 +4,15 @@ menu "ALSA ARM devices"
        depends on SND!=n && ARM
 
 config SND_SA11XX_UDA1341
-       tristate "SA11xx UDA1341TS driver (H3600)"
+       tristate "SA11xx UDA1341TS driver (iPaq H3600)"
        depends on ARCH_SA1100 && SND && L3
        select SND_PCM
        help
-         Say Y or M if you have a Compaq iPaq H3x00 handheld computer and want
-         to use its Philips UDA 1341 audio chip.
+         Say Y here if you have a Compaq iPaq H3x00 handheld computer
+         and want to use its Philips UDA 1341 audio chip.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-sa11xx-uda1341.
 
 endmenu
 
index db1e257..f3338d9 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/time.h>
 #include <linux/smp_lock.h>
+#include <linux/utsname.h>
+#include <linux/config.h>
+
 #include <sound/core.h>
+#include <sound/version.h>
 #include <sound/minors.h>
 #include <sound/info.h>
-#include <sound/version.h>
 #include <linux/proc_fs.h>
 #include <linux/devfs_fs_kernel.h>
 #include <stdarg.h>
@@ -959,7 +962,7 @@ static snd_info_entry_t *snd_info_version_entry = NULL;
 
 static void snd_info_version_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
 {
-       static char *kernel_version = UTS_RELEASE;
+       static char *kernel_version = system_utsname.release;
 
        snd_iprintf(buffer,
                    "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"
index 21f76c2..bb4150a 100644 (file)
@@ -257,7 +257,7 @@ char *snd_kmalloc_strdup(const char *string, int flags)
  *
  * Returns zero if successful, or non-zero on failure.
  */
-int copy_to_user_fromio(void __user *dst, unsigned long src, size_t count)
+int copy_to_user_fromio(void __user *dst, const void __iomem *src, size_t count)
 {
 #if defined(__i386__) || defined(CONFIG_SPARC32)
        return copy_to_user(dst, (const void*)src, count) ? -EFAULT : 0;
@@ -267,7 +267,7 @@ int copy_to_user_fromio(void __user *dst, unsigned long src, size_t count)
                size_t c = count;
                if (c > sizeof(buf))
                        c = sizeof(buf);
-               memcpy_fromio(buf, (void*)src, c);
+               memcpy_fromio(buf, src, c);
                if (copy_to_user(dst, buf, c))
                        return -EFAULT;
                count -= c;
@@ -288,7 +288,7 @@ int copy_to_user_fromio(void __user *dst, unsigned long src, size_t count)
  *
  * Returns zero if successful, or non-zero on failure.
  */
-int copy_from_user_toio(unsigned long dst, const void __user *src, size_t count)
+int copy_from_user_toio(void __iomem *dst, const void __user *src, size_t count)
 {
 #if defined(__i386__) || defined(CONFIG_SPARC32)
        return copy_from_user((void*)dst, src, count) ? -EFAULT : 0;
@@ -300,7 +300,7 @@ int copy_from_user_toio(unsigned long dst, const void __user *src, size_t count)
                        c = sizeof(buf);
                if (copy_from_user(buf, src, c))
                        return -EFAULT;
-               memcpy_toio((void*)dst, buf, c);
+               memcpy_toio(dst, buf, c);
                count -= c;
                dst += c;
                src += c;
index d25dad4..4a271bf 100644 (file)
@@ -267,7 +267,7 @@ const char *snd_pcm_oss_format_name(int format)
 }
 #endif
 
-
+#ifdef CONFIG_PROC_FS
 static void snd_pcm_proc_info_read(snd_pcm_substream_t *substream, snd_info_buffer_t *buffer)
 {
        snd_pcm_info_t info;
@@ -391,6 +391,7 @@ static void snd_pcm_substream_proc_status_read(snd_info_entry_t *entry, snd_info
        snd_iprintf(buffer, "hw_ptr      : %ld\n", runtime->status->hw_ptr);
        snd_iprintf(buffer, "appl_ptr    : %ld\n", runtime->control->appl_ptr);
 }
+#endif
 
 #ifdef CONFIG_SND_DEBUG
 static void snd_pcm_xrun_debug_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
index 0545ff8..4d80f39 100644 (file)
@@ -41,6 +41,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/seq_device.h>
+#include <sound/seq_kernel.h>
 #include <sound/initval.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
@@ -125,11 +126,31 @@ static void snd_seq_device_info(snd_info_entry_t *entry, snd_info_buffer_t * buf
  * load all registered drivers (called from seq_clientmgr.c)
  */
 
+#ifdef CONFIG_KMOD
+/* avoid auto-loading during module_init() */
+static int snd_seq_in_init;
+void snd_seq_autoload_lock(void)
+{
+       snd_seq_in_init++;
+}
+
+void snd_seq_autoload_unlock(void)
+{
+       snd_seq_in_init--;
+}
+#endif
+
 void snd_seq_device_load_drivers(void)
 {
 #ifdef CONFIG_KMOD
        struct list_head *head;
 
+       /* Calling request_module during module_init()
+        * may cause blocking.
+        */
+       if (snd_seq_in_init)
+               return;
+
        if (! current->fs->root)
                return;
 
@@ -309,12 +330,16 @@ int snd_seq_device_register_driver(char *id, snd_seq_dev_ops_t *entry, int argsi
            entry->init_device == NULL || entry->free_device == NULL)
                return -EINVAL;
 
+       snd_seq_autoload_lock();
        ops = find_driver(id, 1);
-       if (ops == NULL)
+       if (ops == NULL) {
+               snd_seq_autoload_unlock();
                return -ENOMEM;
+       }
        if (ops->driver & DRIVER_LOADED) {
                snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id);
                unlock_driver(ops);
+               snd_seq_autoload_unlock();
                return -EBUSY;
        }
 
@@ -332,6 +357,7 @@ int snd_seq_device_register_driver(char *id, snd_seq_dev_ops_t *entry, int argsi
        up(&ops->reg_mutex);
 
        unlock_driver(ops);
+       snd_seq_autoload_unlock();
 
        return 0;
 }
@@ -543,3 +569,7 @@ EXPORT_SYMBOL(snd_seq_device_load_drivers);
 EXPORT_SYMBOL(snd_seq_device_new);
 EXPORT_SYMBOL(snd_seq_device_register_driver);
 EXPORT_SYMBOL(snd_seq_device_unregister_driver);
+#ifdef CONFIG_KMOD
+EXPORT_SYMBOL(snd_seq_autoload_lock);
+EXPORT_SYMBOL(snd_seq_autoload_unlock);
+#endif
index 9ff4df2..3b2bee1 100644 (file)
@@ -30,8 +30,14 @@ config SND_DUMMY
        depends on SND
        select SND_PCM
        help
-         Say 'Y' or 'M' to include dummy driver. This driver does nothing, but
-         emulates various mixer controls and PCM devices.
+         Say Y here to include the dummy driver.  This driver does
+         nothing, but emulates various mixer controls and PCM devices.
+
+         You don't need this unless you're testing the hardware support
+         of programs using the ALSA API.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-dummy.
 
 config SND_VIRMIDI
        tristate "Virtual MIDI soundcard"
@@ -39,8 +45,14 @@ config SND_VIRMIDI
        select SND_TIMER
        select SND_RAWMIDI
        help
-         Say 'Y' or 'M' to include virtual MIDI driver. This driver allows to
-         connect applications using raw MIDI devices to sequencer.
+         Say Y here to include the virtual MIDI driver.  This driver
+         allows to connect applications using raw MIDI devices to
+         sequencer clients.
+
+         If you don't know what MIDI is, say N here.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-virmidi.
 
 config SND_MTPAV
        tristate "MOTU MidiTimePiece AV multiport MIDI"
@@ -48,23 +60,39 @@ config SND_MTPAV
        select SND_TIMER
        select SND_RAWMIDI
        help
-         Say 'Y' or 'M' to include support for MOTU MidiTimePiece AV multiport
-         MIDI adapter.
+         To use a MOTU MidiTimePiece AV multiport MIDI adapter
+         connected to the parallel port, say Y here and make sure that
+         the standard parallel port driver isn't used for the port.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-mtpav.
 
 config SND_SERIAL_U16550
-       tristate "UART16550 - MIDI only driver"
+       tristate "UART16550 serial MIDI driver"
        depends on SND
        select SND_TIMER
        select SND_RAWMIDI
        help
-         Say 'Y' or 'M' to include support for MIDI serial port driver. It works
-         with serial UARTs 16550 and better.
+         To include support for MIDI serial port interfaces, say Y here
+         and read <file:Documentation/sound/alsa/serial-u16550.txt>.
+         This driver works with serial UARTs 16550 and better.
+
+         This driver accesses the serial port hardware directly, so
+         make sure that the standard serial driver isn't used or
+         deactivated with setserial before loading this driver.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-serial-u16550.
 
 config SND_MPU401
        tristate "Generic MPU-401 UART driver"
        depends on SND
        select SND_MPU401_UART
        help
-         Say 'Y' or 'M' to include support for MPU401 hardware using UART access.
+         Say Y here to include support for MIDI ports compatible with
+         the Roland MPU-401 interface in UART mode.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-mpu401.
 
 endmenu
index 0e15942..ef36d9e 100644 (file)
@@ -70,12 +70,12 @@ static unsigned char mpu401_read_port(mpu401_t *mpu, unsigned long addr)
 
 static void mpu401_write_mmio(mpu401_t *mpu, unsigned char data, unsigned long addr)
 {
-       writeb(data, (unsigned long*)addr);
+       writeb(data, (void __iomem *)addr);
 }
 
 static unsigned char mpu401_read_mmio(mpu401_t *mpu, unsigned long addr)
 {
-       return readb((unsigned long*)addr);
+       return readb((void __iomem *)addr);
 }
 /*  */
 
index 964a6b4..e04affc 100644 (file)
@@ -104,7 +104,7 @@ typedef struct ad1889_state {
 } ad1889_state_t;
 
 typedef struct ad1889_dev {
-       unsigned long regbase;
+       void __iomem *regbase;
        struct pci_dev *pci;
        
        spinlock_t lock;
index 8976224..a331e87 100644 (file)
@@ -311,7 +311,6 @@ struct ali_card {
        u16 pci_id;
 #ifdef CONFIG_PM
        u16 pm_suspended;
-       u32 pm_save_state[64 / sizeof(u32)];
        int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
 #endif
        /* soundcore stuff */
@@ -934,7 +933,7 @@ static int alloc_dmabuf(struct ali_state *state)
        dmabuf->rawbuf = rawbuf;
        dmabuf->buforder = order;
 
-       /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+       /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
        pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
        for (page = virt_to_page(rawbuf); page <= pend; page++)
                SetPageReserved(page);
@@ -1955,7 +1954,9 @@ static int ali_mmap(struct file *file, struct vm_area_struct *vma)
        if (size > (PAGE_SIZE << dmabuf->buforder))
                goto out;
        ret = -EAGAIN;
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot))
+       if (remap_pfn_range(vma, vma->vm_start,
+                               virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
+                               size, vma->vm_page_prot))
                goto out;
        dmabuf->mapped = 1;
        dmabuf->trigger = 0;
@@ -3576,7 +3577,7 @@ static int ali_pm_suspend(struct pci_dev *dev, u32 pm_state)
                        }
                }
        }
-       pci_save_state(dev, card->pm_save_state);       /* XXX do we need this? */
+       pci_save_state(dev);    /* XXX do we need this? */
        pci_disable_device(dev);        /* disable busmastering */
        pci_set_power_state(dev, 3);    /* Zzz. */
        return 0;
@@ -3588,7 +3589,7 @@ static int ali_pm_resume(struct pci_dev *dev)
        int num_ac97, i = 0;
        struct ali_card *card = pci_get_drvdata(dev);
        pci_enable_device(dev);
-       pci_restore_state(dev, card->pm_save_state);
+       pci_restore_state(dev);
        /* observation of a toshiba portege 3440ct suggests that the 
           hardware has to be more or less completely reinitialized from
           scratch after an apm suspend.  Works For Me.   -dan */
@@ -3714,11 +3715,7 @@ static int __init ali_init_module(void)
                        controller_pcmout_share_spdif_locked = 0;
                }
        }
-       if (!pci_register_driver(&ali_pci_driver)) {
-               pci_unregister_driver(&ali_pci_driver);
-               return -ENODEV;
-       }
-       return 0;
+       return pci_register_driver(&ali_pci_driver);
 }
 
 static void __exit ali_cleanup_module(void)
index c5d220e..9b2d8ed 100644 (file)
@@ -629,7 +629,7 @@ static int prog_dmabuf(struct au1000_state *s, struct dmabuf *db)
                        return -ENOMEM;
                db->buforder = order;
                /* now mark the pages as reserved;
-                  otherwise remap_page_range doesn't do what we want */
+                  otherwise remap_pfn_range doesn't do what we want */
                pend = virt_to_page(db->rawbuf +
                                    (PAGE_SIZE << db->buforder) - 1);
                for (page = virt_to_page(db->rawbuf); page <= pend; page++)
@@ -1338,7 +1338,8 @@ static int au1000_mmap(struct file *file, struct vm_area_struct *vma)
                ret = -EINVAL;
                goto out;
        }
-       if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf),
+       if (remap_pfn_range(vma->vm_start,
+                            virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
                             size, vma->vm_page_prot)) {
                ret = -EAGAIN;
                goto out;
index 0d76e78..67f8652 100644 (file)
@@ -104,7 +104,7 @@ struct btaudio {
        struct pci_dev *pci;
        unsigned int   irq;
        unsigned long  mem;
-       unsigned long  *mmio;
+       unsigned long  __iomem *mmio;
 
        /* locking */
        int            users;
index a6f09cc..947e5f9 100644 (file)
@@ -221,7 +221,8 @@ struct cs4281_state {
 
        // hardware resources 
        unsigned int pBA0phys, pBA1phys;
-       char *pBA0, *pBA1;
+       char __iomem *pBA0;
+       char __iomem *pBA1;
        unsigned int irq;
 
        // mixer registers 
@@ -1755,7 +1756,7 @@ static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db)
                }
                db->buforder = order;
                // Now mark the pages as reserved; otherwise the 
-               // remap_page_range() in cs4281_mmap doesn't work.
+               // remap_pfn_range() in cs4281_mmap doesn't work.
                // 1. get index to last page in mem_map array for rawbuf.
                mapend = virt_to_page(db->rawbuf + 
                        (PAGE_SIZE << db->buforder) - 1);
@@ -1778,7 +1779,7 @@ static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db)
                }
                s->buforder_tmpbuff = order;
                // Now mark the pages as reserved; otherwise the 
-               // remap_page_range() in cs4281_mmap doesn't work.
+               // remap_pfn_range() in cs4281_mmap doesn't work.
                // 1. get index to last page in mem_map array for rawbuf.
                mapend = virt_to_page(s->tmpbuff + 
                                (PAGE_SIZE << s->buforder_tmpbuff) - 1);
@@ -3135,9 +3136,10 @@ static int cs4281_mmap(struct file *file, struct vm_area_struct *vma)
        size = vma->vm_end - vma->vm_start;
        if (size > (PAGE_SIZE << db->buforder))
                return -EINVAL;
-       if (remap_page_range
-           (vma, vma->vm_start, virt_to_phys(db->rawbuf), size,
-            vma->vm_page_prot)) return -EAGAIN;
+       if (remap_pfn_range(vma, vma->vm_start,
+                               virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+                               size, vma->vm_page_prot))
+               return -EAGAIN;
        db->mapped = 1;
 
        CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
index c212b94..a4141e3 100644 (file)
@@ -346,17 +346,17 @@ struct cs_card {
        u32 irq;
        
        /* mappings */
-       void *ba0;
+       void __iomem *ba0;
        union
        {
                struct
                {
-                       u8 *data0;
-                       u8 *data1;
-                       u8 *pmem;
-                       u8 *reg;
+                       u8 __iomem *data0;
+                       u8 __iomem *data1;
+                       u8 __iomem *pmem;
+                       u8 __iomem *reg;
                } name;
-               u8 *idx[4];
+               u8 __iomem *idx[4];
        } ba1;
        
        /* Function support */
@@ -1190,7 +1190,7 @@ static int alloc_dmabuf(struct cs_state *state)
        dmabuf->buforder = order;
        dmabuf->rawbuf = rawbuf;
        // Now mark the pages as reserved; otherwise the 
-       // remap_page_range() in cs46xx_mmap doesn't work.
+       // remap_pfn_range() in cs46xx_mmap doesn't work.
        // 1. get index to last page in mem_map array for rawbuf.
        mapend = virt_to_page(dmabuf->rawbuf + 
                (PAGE_SIZE << dmabuf->buforder) - 1);
@@ -1227,7 +1227,7 @@ static int alloc_dmabuf(struct cs_state *state)
        dmabuf->buforder_tmpbuff = order;
        
        // Now mark the pages as reserved; otherwise the 
-       // remap_page_range() in cs46xx_mmap doesn't work.
+       // remap_pfn_range() in cs46xx_mmap doesn't work.
        // 1. get index to last page in mem_map array for rawbuf.
        mapend = virt_to_page(dmabuf->tmpbuff + 
                (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
@@ -2452,7 +2452,8 @@ static int cs_mmap(struct file *file, struct vm_area_struct *vma)
                ret = -EINVAL;
                goto out;
        }
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+       if (remap_pfn_range(vma, vma->vm_start,
+                            virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
                             size, vma->vm_page_prot))
        {
                ret = -EAGAIN;
@@ -4308,7 +4309,7 @@ static int __init cs_ac97_init(struct cs_card *card)
 static void cs461x_download_image(struct cs_card *card)
 {
     unsigned i, j, temp1, temp2, offset, count;
-    unsigned char *pBA1 = ioremap(card->ba1_addr, 0x40000);
+    unsigned char __iomem *pBA1 = ioremap(card->ba1_addr, 0x40000);
     for( i=0; i < CLEAR__COUNT; i++)
     {
         offset = ClrStat[i].BA1__DestByteOffset;
index 57f9bc1..df8f0e3 100644 (file)
@@ -573,7 +573,7 @@ static int prog_dmabuf(struct es1370_state *s, struct dmabuf *db, unsigned rate,
                if (!db->rawbuf)
                        return -ENOMEM;
                db->buforder = order;
-               /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+               /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
                pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
                for (page = virt_to_page(db->rawbuf); page <= pend; page++)
                        SetPageReserved(page);
@@ -1364,7 +1364,9 @@ static int es1370_mmap(struct file *file, struct vm_area_struct *vma)
                ret = -EINVAL;
                goto out;
        }
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
+       if (remap_pfn_range(vma, vma->vm_start,
+                               virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+                               size, vma->vm_page_prot)) {
                ret = -EAGAIN;
                goto out;
        }
@@ -1940,7 +1942,9 @@ static int es1370_mmap_dac(struct file *file, struct vm_area_struct *vma)
        if (size > (PAGE_SIZE << s->dma_dac1.buforder))
                goto out;
        ret = -EAGAIN;
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
+       if (remap_pfn_range(vma, vma->vm_start,
+                       virt_to_phys(s->dma_dac1.rawbuf) >> PAGE_SHIFT,
+                       size, vma->vm_page_prot))
                goto out;
        s->dma_dac1.mapped = 1;
        ret = 0;
index d6b59fb..b6d943e 100644 (file)
@@ -637,7 +637,7 @@ static void set_dac2_rate(struct es1371_state *s, unsigned rate)
 
 /* --------------------------------------------------------------------- */
 
-static void __init src_init(struct es1371_state *s)
+static void __devinit src_init(struct es1371_state *s)
 {
         unsigned int i;
 
@@ -910,7 +910,7 @@ static int prog_dmabuf(struct es1371_state *s, struct dmabuf *db, unsigned rate,
                if (!db->rawbuf)
                        return -ENOMEM;
                db->buforder = order;
-               /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+               /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
                pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
                for (page = virt_to_page(db->rawbuf); page <= pend; page++)
                        SetPageReserved(page);
@@ -1555,7 +1555,9 @@ static int es1371_mmap(struct file *file, struct vm_area_struct *vma)
                ret = -EINVAL;
                goto out;
        }
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
+       if (remap_pfn_range(vma, vma->vm_start,
+                               virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+                               size, vma->vm_page_prot)) {
                ret = -EAGAIN;
                goto out;
        }
@@ -2128,7 +2130,9 @@ static int es1371_mmap_dac(struct file *file, struct vm_area_struct *vma)
        if (size > (PAGE_SIZE << s->dma_dac1.buforder))
                goto out;
        ret = -EAGAIN;
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
+       if (remap_pfn_range(vma, vma->vm_start,
+                       virt_to_phys(s->dma_dac1.rawbuf) >> PAGE_SHIFT,
+                       size, vma->vm_page_prot))
                goto out;
        s->dma_dac1.mapped = 1;
        ret = 0;
@@ -2754,7 +2758,7 @@ MODULE_LICENSE("GPL");
 static struct initvol {
        int mixch;
        int vol;
-} initvol[] __initdata = {
+} initvol[] __devinitdata = {
        { SOUND_MIXER_WRITE_LINE, 0x4040 },
        { SOUND_MIXER_WRITE_CD, 0x4040 },
        { MIXER_WRITE(SOUND_MIXER_VIDEO), 0x4040 },
index 3002cbe..3e73405 100644 (file)
@@ -445,7 +445,7 @@ static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db)
                if (!db->rawbuf)
                        return -ENOMEM;
                db->buforder = order;
-               /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+               /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
                pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
                for (page = virt_to_page(db->rawbuf); page <= pend; page++)
                        SetPageReserved(page);
@@ -1242,7 +1242,9 @@ static int solo1_mmap(struct file *file, struct vm_area_struct *vma)
        if (size > (PAGE_SIZE << db->buforder))
                goto out;
        ret = -EAGAIN;
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+       if (remap_pfn_range(vma, vma->vm_start,
+                               virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+                               size, vma->vm_page_prot))
                goto out;
        db->mapped = 1;
        ret = 0;
@@ -2451,11 +2453,7 @@ static struct pci_driver solo1_driver = {
 static int __init init_solo1(void)
 {
        printk(KERN_INFO "solo1: version v0.20 time " __TIME__ " " __DATE__ "\n");
-       if (!pci_register_driver(&solo1_driver)) {
-               pci_unregister_driver(&solo1_driver);
-                return -ENODEV;
-       }
-       return 0;
+       return pci_register_driver(&solo1_driver);
 }
 
 /* --------------------------------------------------------------------- */
index 67b2bbb..9f15f30 100644 (file)
@@ -1409,7 +1409,8 @@ forte_dsp_mmap (struct file *file, struct vm_area_struct *vma)
                 goto out;
        }
 
-        if (remap_page_range (vma, vma->vm_start, virt_to_phys (channel->buf),
+        if (remap_pfn_range(vma, vma->vm_start,
+                             virt_to_phys(channel->buf) >> PAGE_SHIFT,
                              size, vma->vm_page_prot)) {
                DPRINTK ("%s: remap el a no worko\n", __FUNCTION__);
                ret = -EAGAIN;
@@ -2111,12 +2112,7 @@ forte_init_module (void)
 {
        printk (KERN_INFO PFX DRIVER_VERSION "\n");
 
-       if (!pci_register_driver (&forte_pci_driver)) {
-               pci_unregister_driver (&forte_pci_driver);
-               return -ENODEV;
-       }
-
-       return 0;
+       return pci_register_driver (&forte_pci_driver);
 }
 
 
index f984133..57718fe 100644 (file)
@@ -693,7 +693,7 @@ static int prog_dmabuf(struct it8172_state *s, struct dmabuf *db,
                        return -ENOMEM;
                db->buforder = order;
                /* now mark the pages as reserved;
-                  otherwise remap_page_range doesn't do what we want */
+                  otherwise remap_pfn_range doesn't do what we want */
                pend = virt_to_page(db->rawbuf +
                                    (PAGE_SIZE << db->buforder) - 1);
                for (page = virt_to_page(db->rawbuf); page <= pend; page++)
@@ -1311,7 +1311,8 @@ static int it8172_mmap(struct file *file, struct vm_area_struct *vma)
                unlock_kernel();
                return -EINVAL;
        }
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf),
+       if (remap_pfn_range(vma, vma->vm_start,
+                            virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
                             size, vma->vm_page_prot)) {
                unlock_kernel();
                return -EAGAIN;
index 66456db..84fe23d 100644 (file)
@@ -2520,7 +2520,9 @@ static int ess_mmap(struct file *file, struct vm_area_struct *vma)
        if (size > (PAGE_SIZE << db->buforder))
                goto out;
        ret = -EAGAIN;
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+       if (remap_pfn_range(vma, vma->vm_start,
+                       virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+                       size, vma->vm_page_prot))
                goto out;
        db->mapped = 1;
        ret = 0;
@@ -2953,7 +2955,7 @@ allocate_buffers(struct ess_state *s)
 
        }
 
-       /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+       /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
        pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
        for (page = virt_to_page(rawbuf); page <= pend; page++)
                SetPageReserved(page);
index c27e88f..d2573bb 100644 (file)
@@ -1557,7 +1557,9 @@ static int m3_mmap(struct file *file, struct vm_area_struct *vma)
      * ask Jeff what the hell I'm doing wrong.
      */
     ret = -EAGAIN;
-    if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+    if (remap_pfn_range(vma, vma->vm_start,
+                       virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+                       size, vma->vm_page_prot))
         goto out;
 
     db->mapped = 1;
@@ -2940,8 +2942,7 @@ static int __init m3_init_module(void)
         return -ENODEV; /* ? */
     }
 
-    if (!pci_register_driver(&m3_pci_driver)) {
-        pci_unregister_driver(&m3_pci_driver);
+    if (pci_register_driver(&m3_pci_driver)) {
         unregister_reboot_notifier(&m3_reboot_nb);
         return -ENODEV;
     }
index 7ebc5d3..9f18b40 100644 (file)
@@ -109,18 +109,18 @@ static void reset_play_queue(void)
        LPDAQD lpDAQ;
 
        dev.last_playbank = -1;
-       isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead);
-       isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail);
+       writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead);
+       writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail);
 
        for (n = 0, lpDAQ = dev.base + DAPQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
-               isa_writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
-               isa_writew(0, lpDAQ + DAQDS_wSize);
-               isa_writew(1, lpDAQ + DAQDS_wFormat);
-               isa_writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize);
-               isa_writew(dev.play_channels, lpDAQ + DAQDS_wChannels);
-               isa_writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate);
-               isa_writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
-               isa_writew(n, lpDAQ + DAQDS_wFlags);
+               writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
+               writew(0, lpDAQ + DAQDS_wSize);
+               writew(1, lpDAQ + DAQDS_wFormat);
+               writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize);
+               writew(dev.play_channels, lpDAQ + DAQDS_wChannels);
+               writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate);
+               writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
+               writew(n, lpDAQ + DAQDS_wFlags);
        }
 }
 
@@ -131,25 +131,25 @@ static void reset_record_queue(void)
        unsigned long flags;
 
        dev.last_recbank = 2;
-       isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead);
-       isa_writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail);
+       writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead);
+       writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail);
 
        /* Critical section: bank 1 access */
        spin_lock_irqsave(&dev.lock, flags);
        msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS);
-       isa_memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+       memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
        msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
        spin_unlock_irqrestore(&dev.lock, flags);
 
        for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
-               isa_writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
-               isa_writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
-               isa_writew(1, lpDAQ + DAQDS_wFormat);
-               isa_writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize);
-               isa_writew(dev.rec_channels, lpDAQ + DAQDS_wChannels);
-               isa_writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate);
-               isa_writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
-               isa_writew(n, lpDAQ + DAQDS_wFlags);
+               writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
+               writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
+               writew(1, lpDAQ + DAQDS_wFormat);
+               writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize);
+               writew(dev.rec_channels, lpDAQ + DAQDS_wChannels);
+               writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate);
+               writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
+               writew(n, lpDAQ + DAQDS_wFlags);
        }
 }
 
@@ -185,9 +185,9 @@ static int dsp_set_format(struct file *file, int val)
 
        for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
                if (file->f_mode & FMODE_WRITE)
-                       isa_writew(data, lpDAQ + DAQDS_wSampleSize);
+                       writew(data, lpDAQ + DAQDS_wSampleSize);
                if (file->f_mode & FMODE_READ)
-                       isa_writew(data, lpDARQ + DAQDS_wSampleSize);
+                       writew(data, lpDARQ + DAQDS_wSampleSize);
        }
        if (file->f_mode & FMODE_WRITE)
                dev.play_sample_size = data;
@@ -318,9 +318,9 @@ static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
                        if (file->f_mode & FMODE_WRITE)
-                               isa_writew(data, lpDAQ + DAQDS_wSampleRate);
+                               writew(data, lpDAQ + DAQDS_wSampleRate);
                        if (file->f_mode & FMODE_READ)
-                               isa_writew(data, lpDARQ + DAQDS_wSampleRate);
+                               writew(data, lpDARQ + DAQDS_wSampleRate);
                }
                if (file->f_mode & FMODE_WRITE)
                        dev.play_sample_rate = data;
@@ -361,9 +361,9 @@ static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
                        if (file->f_mode & FMODE_WRITE)
-                               isa_writew(data, lpDAQ + DAQDS_wChannels);
+                               writew(data, lpDAQ + DAQDS_wChannels);
                        if (file->f_mode & FMODE_READ)
-                               isa_writew(data, lpDARQ + DAQDS_wChannels);
+                               writew(data, lpDARQ + DAQDS_wChannels);
                }
                if (file->f_mode & FMODE_WRITE)
                        dev.play_channels = data;
@@ -401,27 +401,27 @@ static int mixer_get(int d)
 }
 
 #define update_volm(a,b)                                               \
-       isa_writew((dev.left_levels[a] >> 1) *                          \
-              isa_readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff,      \
+       writew((dev.left_levels[a] >> 1) *                              \
+              readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff,  \
               dev.SMA + SMA_##b##Left);                                \
-       isa_writew((dev.right_levels[a] >> 1)  *                        \
-              isa_readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff,     \
+       writew((dev.right_levels[a] >> 1)  *                    \
+              readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \
               dev.SMA + SMA_##b##Right);
 
 #define update_potm(d,s,ar)                                            \
-       isa_writeb((dev.left_levels[d] >> 8) *                          \
-              isa_readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff,      \
+       writeb((dev.left_levels[d] >> 8) *                              \
+              readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff,  \
               dev.SMA + SMA_##s##Left);                                \
-       isa_writeb((dev.right_levels[d] >> 8) *                         \
-              isa_readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff,     \
+       writeb((dev.right_levels[d] >> 8) *                             \
+              readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \
               dev.SMA + SMA_##s##Right);                               \
        if (msnd_send_word(&dev, 0, 0, ar) == 0)                        \
                chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
 
 #define update_pot(d,s,ar)                             \
-       isa_writeb(dev.left_levels[d] >> 8,             \
+       writeb(dev.left_levels[d] >> 8,         \
               dev.SMA + SMA_##s##Left);                \
-       isa_writeb(dev.right_levels[d] >> 8,            \
+       writeb(dev.right_levels[d] >> 8,                \
               dev.SMA + SMA_##s##Right);               \
        if (msnd_send_word(&dev, 0, 0, ar) == 0)        \
                chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
@@ -450,23 +450,23 @@ static int mixer_set(int d, int value)
                /* master volume unscaled controls */
        case SOUND_MIXER_LINE:                  /* line pot control */
                /* scaled by IMIX in digital mix */
-               isa_writeb(bLeft, dev.SMA + SMA_bInPotPosLeft);
-               isa_writeb(bRight, dev.SMA + SMA_bInPotPosRight);
+               writeb(bLeft, dev.SMA + SMA_bInPotPosLeft);
+               writeb(bRight, dev.SMA + SMA_bInPotPosRight);
                if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
                        chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
                break;
 #ifndef MSND_CLASSIC
        case SOUND_MIXER_MIC:                   /* mic pot control */
                /* scaled by IMIX in digital mix */
-               isa_writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft);
-               isa_writeb(bRight, dev.SMA + SMA_bMicPotPosRight);
+               writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft);
+               writeb(bRight, dev.SMA + SMA_bMicPotPosRight);
                if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
                        chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
                break;
 #endif
        case SOUND_MIXER_VOLUME:                /* master volume */
-               isa_writew(wLeft, dev.SMA + SMA_wCurrMastVolLeft);
-               isa_writew(wRight, dev.SMA + SMA_wCurrMastVolRight);
+               writew(wLeft, dev.SMA + SMA_wCurrMastVolLeft);
+               writew(wRight, dev.SMA + SMA_wCurrMastVolRight);
                /* fall through */
 
        case SOUND_MIXER_LINE1:                 /* aux pot control */
@@ -815,25 +815,25 @@ static __inline__ int pack_DARQ_to_DARF(register int bank)
        LPDAQD DAQD;
 
        /* Increment the tail and check for queue wrap */
-       wTmp = isa_readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
-       if (wTmp > isa_readw(dev.DARQ + JQS_wSize))
+       wTmp = readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+       if (wTmp > readw(dev.DARQ + JQS_wSize))
                wTmp = 0;
-       while (wTmp == isa_readw(dev.DARQ + JQS_wHead) && timeout--)
+       while (wTmp == readw(dev.DARQ + JQS_wHead) && timeout--)
                udelay(1);
-       isa_writew(wTmp, dev.DARQ + JQS_wTail);
+       writew(wTmp, dev.DARQ + JQS_wTail);
 
        /* Get our digital audio queue struct */
        DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF;
 
        /* Get length of data */
-       size = isa_readw(DAQD + DAQDS_wSize);
+       size = readw(DAQD + DAQDS_wSize);
 
        /* Read data from the head (unprotected bank 1 access okay
            since this is only called inside an interrupt) */
        msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS);
-       msnd_fifo_write(
+       msnd_fifo_write_io(
                &dev.DARF,
-               (char *)(dev.base + bank * DAR_BUFF_SIZE),
+               dev.base + bank * DAR_BUFF_SIZE,
                size);
        msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
 
@@ -846,8 +846,8 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start)
        register int protect = start, nbanks = 0;
        LPDAQD DAQD;
 
-       DAPQ_tail = isa_readw(dev.DAPQ + JQS_wTail);
-       while (DAPQ_tail != isa_readw(dev.DAPQ + JQS_wHead) || start) {
+       DAPQ_tail = readw(dev.DAPQ + JQS_wTail);
+       while (DAPQ_tail != readw(dev.DAPQ + JQS_wHead) || start) {
                register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
                register int n;
                unsigned long flags;
@@ -856,15 +856,15 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start)
                if (protect) {
                        /* Critical section: protect fifo in non-interrupt */
                        spin_lock_irqsave(&dev.lock, flags);
-                       n = msnd_fifo_read(
+                       n = msnd_fifo_read_io(
                                &dev.DAPF,
-                               (char *)(dev.base + bank_num * DAP_BUFF_SIZE),
+                               dev.base + bank_num * DAP_BUFF_SIZE,
                                DAP_BUFF_SIZE);
                        spin_unlock_irqrestore(&dev.lock, flags);
                } else {
-                       n = msnd_fifo_read(
+                       n = msnd_fifo_read_io(
                                &dev.DAPF,
-                               (char *)(dev.base + bank_num * DAP_BUFF_SIZE),
+                               dev.base + bank_num * DAP_BUFF_SIZE,
                                DAP_BUFF_SIZE);
                }
                if (!n)
@@ -877,12 +877,12 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start)
                DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF;
 
                /* Write size of this bank */
-               isa_writew(n, DAQD + DAQDS_wSize);
+               writew(n, DAQD + DAQDS_wSize);
                ++nbanks;
 
                /* Then advance the tail */
                DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
-               isa_writew(DAPQ_tail, dev.DAPQ + JQS_wTail);
+               writew(DAPQ_tail, dev.DAPQ + JQS_wTail);
                /* Tell the DSP to play the bank */
                msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
        }
@@ -1094,15 +1094,15 @@ static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *regs)
        msnd_inb(dev.io + HP_RXL);
 
        /* Evaluate queued DSP messages */
-       while (isa_readw(dev.DSPQ + JQS_wTail) != isa_readw(dev.DSPQ + JQS_wHead)) {
+       while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) {
                register WORD wTmp;
 
-               eval_dsp_msg(isa_readw(dev.pwDSPQData + 2*isa_readw(dev.DSPQ + JQS_wHead)));
+               eval_dsp_msg(readw(dev.pwDSPQData + 2*readw(dev.DSPQ + JQS_wHead)));
 
-               if ((wTmp = isa_readw(dev.DSPQ + JQS_wHead) + 1) > isa_readw(dev.DSPQ + JQS_wSize))
-                       isa_writew(0, dev.DSPQ + JQS_wHead);
+               if ((wTmp = readw(dev.DSPQ + JQS_wHead) + 1) > readw(dev.DSPQ + JQS_wSize))
+                       writew(0, dev.DSPQ + JQS_wHead);
                else
-                       isa_writew(wTmp, dev.DSPQ + JQS_wHead);
+                       writew(wTmp, dev.DSPQ + JQS_wHead);
        }
        return IRQ_HANDLED;
 }
@@ -1182,7 +1182,7 @@ static int __init probe_multisound(void)
        }
        printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
 #endif /* MSND_CLASSIC */
-              "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
+              "I/O 0x%x-0x%x, IRQ %d, memory mapped to %p-%p\n",
               dev.name,
 #ifndef MSND_CLASSIC
               rev, xv,
@@ -1206,16 +1206,16 @@ static int init_sma(void)
 #endif
        msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
        if (initted) {
-               mastVolLeft = isa_readw(dev.SMA + SMA_wCurrMastVolLeft);
-               mastVolRight = isa_readw(dev.SMA + SMA_wCurrMastVolRight);
+               mastVolLeft = readw(dev.SMA + SMA_wCurrMastVolLeft);
+               mastVolRight = readw(dev.SMA + SMA_wCurrMastVolRight);
        } else
                mastVolLeft = mastVolRight = 0;
-       isa_memset_io(dev.base, 0, 0x8000);
+       memset_io(dev.base, 0, 0x8000);
 
        /* Critical section: bank 1 access */
        spin_lock_irqsave(&dev.lock, flags);
        msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS);
-       isa_memset_io(dev.base, 0, 0x8000);
+       memset_io(dev.base, 0, 0x8000);
        msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
        spin_unlock_irqrestore(&dev.lock, flags);
 
@@ -1248,19 +1248,19 @@ static int init_sma(void)
 
        /* Setup some DSP values */
 #ifndef MSND_CLASSIC
-       isa_writew(1, dev.SMA + SMA_wCurrPlayFormat);
-       isa_writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
-       isa_writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels);
-       isa_writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
+       writew(1, dev.SMA + SMA_wCurrPlayFormat);
+       writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
+       writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels);
+       writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
 #endif
-       isa_writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD);
-       isa_writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft);
-       isa_writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight);
+       writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD);
+       writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft);
+       writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight);
 #ifndef MSND_CLASSIC
-       isa_writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch);
-       isa_writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate);
+       writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch);
+       writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate);
 #endif
-       isa_writew(0x303, dev.SMA + SMA_wCurrInputTagBits);
+       writew(0x303, dev.SMA + SMA_wCurrInputTagBits);
 
        initted = 1;
 
@@ -1269,12 +1269,12 @@ static int init_sma(void)
 
 static int __init calibrate_adc(WORD srate)
 {
-       isa_writew(srate, dev.SMA + SMA_wCalFreqAtoD);
+       writew(srate, dev.SMA + SMA_wCalFreqAtoD);
        if (dev.calibrate_signal == 0)
-               isa_writew(isa_readw(dev.SMA + SMA_wCurrHostStatusFlags)
+               writew(readw(dev.SMA + SMA_wCurrHostStatusFlags)
                       | 0x0001, dev.SMA + SMA_wCurrHostStatusFlags);
        else
-               isa_writew(isa_readw(dev.SMA + SMA_wCurrHostStatusFlags)
+               writew(readw(dev.SMA + SMA_wCurrHostStatusFlags)
                       & ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags);
        if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
            chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
@@ -1304,7 +1304,7 @@ static int upload_dsp_code(void)
                return -EBUSY;
        }
 #endif
-       isa_memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
+       memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
        if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
                printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
                return -ENODEV;
@@ -1357,7 +1357,7 @@ static int initialize(void)
        }
 
        timeout = 200;
-       while (isa_readw(dev.base)) {
+       while (readw(dev.base)) {
                mdelay(1);
                if (!timeout--) {
                        printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n");
@@ -1861,7 +1861,7 @@ static int __init msnd_init(void)
        dev.io = io;
        dev.numio = DSP_NUMIO;
        dev.irq = irq;
-       dev.base = mem;
+       dev.base = ioremap(mem, 0x8000);
        dev.fifosize = fifosize * 1024;
        dev.calibrate_signal = calibrate_signal ? 1 : 0;
        dev.recsrc = 0;
index 583004e..eae7d99 100644 (file)
@@ -60,7 +60,7 @@ struct nm256_info
        /* Physical address of the port. */
        u32 physaddr;
        /* Our mapped-in pointer. */
-       char *ptr;
+       char __iomem *ptr;
        /* PTR's offset within the physical port.  */
        u32 start_offset;
        /* And the offset of the end of the buffer.  */
@@ -233,14 +233,14 @@ extern int nm256_debug;
 static inline int nm256_writePort##X (struct nm256_info *card,\
                                      int port, int offset, int value)\
 {\
-    u##X *addr;\
+    u##X __iomem *addr;\
 \
     if (nm256_debug > 1)\
         printk (KERN_DEBUG "Writing 0x%x to %d:0x%x\n", value, port, offset);\
 \
     NM_FIX_PORT;\
 \
-    addr = (u##X *)(card->port[port - 1].ptr + offset);\
+    addr = (u##X __iomem *)(card->port[port - 1].ptr + offset);\
     func (value, addr);\
     return 0;\
 }
@@ -253,11 +253,11 @@ DEFwritePortX (32, writel)
 static inline u##X nm256_readPort##X (struct nm256_info *card,\
                                        int port, int offset)\
 {\
-    u##X *addr;\
+    u##X __iomem *addr;\
 \
     NM_FIX_PORT\
 \
-    addr = (u##X *)(card->port[port - 1].ptr + offset);\
+    addr = (u##X __iomem *)(card->port[port - 1].ptr + offset);\
     return func(addr);\
 }
 
index c770137..96cc75a 100644 (file)
@@ -273,7 +273,7 @@ typedef struct _rme96xx_info {
        /* hardware settings */
        int magic;
        struct pci_dev * pcidev; /* pci_dev structure */
-       unsigned long *iobase;  
+       unsigned long __iomem *iobase;  
        unsigned int irq;
 
        /* list of rme96xx devices */
@@ -1685,14 +1685,14 @@ static int rm96xx_mmap(struct file *file, struct vm_area_struct *vma) {
        if (vma->vm_flags & VM_WRITE) {
                if (!s->started) rme96xx_startcard(s,1);
 
-               if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
+               if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
                        unlock_kernel();
                        return -EAGAIN;
                }
        } 
        else if (vma->vm_flags & VM_READ) {
                if (!s->started) rme96xx_startcard(s,1);
-               if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
+               if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
                        unlock_kernel();
                        return -EAGAIN;
                }
index 8bb6dea..70c91dd 100644 (file)
@@ -756,7 +756,7 @@ static int prog_dmabuf(struct sv_state *s, unsigned rec)
                if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
                        printk(KERN_DEBUG "sv: DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 
                               virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
-               /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+               /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
                pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
                for (page = virt_to_page(db->rawbuf); page <= pend; page++)
                        SetPageReserved(page);
@@ -1549,7 +1549,9 @@ static int sv_mmap(struct file *file, struct vm_area_struct *vma)
        if (size > (PAGE_SIZE << db->buforder))
                goto out;
        ret = -EAGAIN;
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+       if (remap_pfn_range(vma, vma->vm_start,
+                               virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+                               size, vma->vm_page_prot))
                goto out;
        db->mapped = 1;
        ret = 0;
index 13bcc76..f552f30 100644 (file)
@@ -334,7 +334,7 @@ static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
        dmabuf->dma_addr = dma_addr;
        dmabuf->buforder = order;
 
-       /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+       /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
        mapend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
        for (map = virt_to_page(rawbuf); map <= mapend; map++)
                set_bit(PG_reserved, &map->flags);
@@ -1545,7 +1545,8 @@ static int ymf_mmap(struct file *file, struct vm_area_struct *vma)
        size = vma->vm_end - vma->vm_start;
        if (size > (PAGE_SIZE << dmabuf->buforder))
                return -EINVAL;
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+       if (remap_pfn_range(vma, vma->vm_start,
+                            virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
                             size, vma->vm_page_prot))
                return -EAGAIN;
        dmabuf->mapped = 1;
index 87a24f0..f810a10 100644 (file)
@@ -239,7 +239,7 @@ struct ymf_capture {
 
 struct ymf_unit {
        u8 rev;                         /* PCI revision */
-       void *reg_area_virt;
+       void __iomem *reg_area_virt;
        void *dma_area_va;
        dma_addr_t dma_area_ba;
        unsigned int dma_area_size;
index 981e60a..01cc80d 100644 (file)
@@ -1,14 +1,15 @@
 # ALSA PA-RISC drivers
 
-menu "ALSA PA-RISC devices"
-       depends on SND!=n && PARISC
+menu "ALSA GSC devices"
+       depends on SND!=n && GSC
 
 config SND_HARMONY
        tristate "Harmony/Vivace sound chip"
        depends on SND
        select SND_PCM
        help
-         Say 'Y' or 'M' to include support for Harmony/Vivace soundchip
-         on HP712s, 715/new and many other GSC based machines.
+         Say 'Y' or 'M' to include support for the Harmony/Vivace sound
+         chip found in most GSC-based PA-RISC workstations.  It's frequently
+         provided as part of the Lasi multi-function IC.
 
 endmenu
index e409d4f..3c32221 100644 (file)
@@ -3,7 +3,12 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-snd-ac97-codec-objs := ac97_codec.o ac97_pcm.o ac97_proc.o ac97_patch.o
+snd-ac97-codec-objs := ac97_codec.o ac97_pcm.o ac97_patch.o
+
+ifneq ($(CONFIG_PROC_FS),)
+snd-ac97-codec-objs += ac97_proc.o
+endif
+
 snd-ak4531-codec-objs := ak4531_codec.o
 
 # Toplevel Module Dependency
index 24a9f6c..dadf387 100644 (file)
@@ -57,3 +57,6 @@
 #define AC97_ID_VT1616         0x49434551
 #define AC97_ID_CM9738         0x434d4941
 #define AC97_ID_CM9739         0x434d4961
+#define AC97_ID_CM9761_78      0x434d4978
+#define AC97_ID_CM9761_82      0x434d4982
+#define AC97_ID_CM9761_83      0x434d4983
index a619d72..641b0be 100644 (file)
@@ -52,6 +52,7 @@ int patch_alc655(ac97_t * ac97);
 int patch_alc850(ac97_t * ac97);
 int patch_cm9738(ac97_t * ac97);
 int patch_cm9739(ac97_t * ac97);
+int patch_cm9761(ac97_t * ac97);
 int patch_vt1616(ac97_t * ac97);
 int patch_it2646(ac97_t * ac97);
 int mpatch_si3036(ac97_t * ac97);
index bec2052..e1ed2e3 100644 (file)
@@ -43,15 +43,14 @@ 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_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for ATI IXP controller.");
-module_param_array(id, charp, boot_devs, 0444);
+module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for ATI IXP controller.");
-module_param_array(enable, bool, boot_devs, 0444);
+module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable audio part of ATI IXP controller.");
-module_param_array(ac97_clock, int, boot_devs, 0444);
+module_param_array(ac97_clock, int, NULL, 0444);
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
 
 
@@ -1143,6 +1142,7 @@ static int snd_atiixp_resume(snd_card_t *card, unsigned int state)
 
        pci_enable_device(chip->pci);
        pci_set_power_state(chip->pci, 0);
+       pci_set_master(chip->pci);
 
        snd_atiixp_aclink_reset(chip);
        snd_atiixp_chip_start(chip);
@@ -1196,6 +1196,7 @@ static int snd_atiixp_free(atiixp_t *chip)
        if (chip->remap_addr)
                iounmap(chip->remap_addr);
        pci_release_regions(chip->pci);
+       pci_disable_device(chip->pci);
        kfree(chip);
        return 0;
 }
@@ -1223,8 +1224,10 @@ static int __devinit snd_atiixp_create(snd_card_t *card,
                return err;
 
        chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL)
+       if (chip == NULL) {
+               pci_disable_device(pci);
                return -ENOMEM;
+       }
 
        spin_lock_init(&chip->reg_lock);
        spin_lock_init(&chip->ac97_lock);
@@ -1234,11 +1237,12 @@ static int __devinit snd_atiixp_create(snd_card_t *card,
        chip->irq = -1;
        if ((err = pci_request_regions(pci, "ATI IXP MC97")) < 0) {
                kfree(chip);
+               pci_disable_device(pci);
                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) {
+       if (chip->remap_addr == NULL) {
                snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
                snd_atiixp_free(chip);
                return -EIO;
index 0bd4b33..0f3ab7a 100644 (file)
@@ -514,7 +514,7 @@ static void cs46xx_dsp_proc_task_tree_read (snd_info_entry_t *entry, snd_info_bu
        cs46xx_t *chip = entry->private_data;
        dsp_spos_instance_t * ins = chip->dsp_spos_instance;
        int i,j,col;
-       unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
+       void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
 
        down(&chip->spos_mutex);
        snd_iprintf(buffer, "TASK TREES:\n");
@@ -573,7 +573,7 @@ static void cs46xx_dsp_proc_parameter_dump_read (snd_info_entry_t *entry, snd_in
        cs46xx_t *chip = entry->private_data;
        /*dsp_spos_instance_t * ins = chip->dsp_spos_instance; */
        unsigned int i,col = 0;
-       unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
+       void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
        symbol_entry_t * symbol; 
 
        for (i = 0;i < DSP_PARAMETER_BYTE_SIZE; i += sizeof(u32),col ++) {
@@ -599,7 +599,7 @@ static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_
 {
        cs46xx_t *chip = entry->private_data;
        int i,col = 0;
-       unsigned long dst = chip->region.idx[2].remap_addr;
+       void __iomem *dst = chip->region.idx[2].remap_addr;
 
        snd_iprintf(buffer,"PCMREADER:\n");
        for (i = PCM_READER_BUF1;i < PCM_READER_BUF1 + 0x30; i += sizeof(u32),col ++) {
@@ -909,12 +909,12 @@ int cs46xx_dsp_proc_done (cs46xx_t *chip)
 static int debug_tree;
 static void _dsp_create_task_tree (cs46xx_t *chip,u32 * task_data, u32  dest, int size)
 {
-       unsigned long spdst = chip->region.idx[1].remap_addr + 
+       void __iomem *spdst = chip->region.idx[1].remap_addr + 
                DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
        int i;
 
        for (i = 0; i < size; ++i) {
-               if (debug_tree) printk ("addr %08x, val %08x\n",(int)spdst,task_data[i]);
+               if (debug_tree) printk ("addr %p, val %08x\n", spdst,task_data[i]);
                writel(task_data[i],spdst);
                spdst += sizeof(u32);
        }
@@ -923,12 +923,12 @@ static void _dsp_create_task_tree (cs46xx_t *chip,u32 * task_data, u32  dest, in
 static int debug_scb;
 static void _dsp_create_scb (cs46xx_t *chip,u32 * scb_data, u32  dest)
 {
-       unsigned long spdst = chip->region.idx[1].remap_addr + 
+       void __iomem *spdst = chip->region.idx[1].remap_addr + 
                DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
        int i;
 
        for (i = 0; i < 0x10; ++i) {
-               if (debug_scb) printk ("addr %08x, val %08x\n",(int)spdst,scb_data[i]);
+               if (debug_scb) printk ("addr %p, val %08x\n", spdst,scb_data[i]);
                writel(scb_data[i],spdst);
                spdst += sizeof(u32);
        }
index 9fbbf6c..080d9d4 100644 (file)
@@ -1092,6 +1092,7 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(snd_kcontrol_t * kcontrol, snd_ct
        emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
        unsigned int nval[2], bits;
        int nefx = emu->audigy ? 64 : 32;
+       int nefxb = emu->audigy ? 7 : 6;
        int change, idx;
        
        nval[0] = nval[1] = 0;
@@ -1100,8 +1101,14 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(snd_kcontrol_t * kcontrol, snd_ct
                        nval[idx / 32] |= 1 << (idx % 32);
                        bits++;
                }
-       if (bits != 1 && bits != 2 && bits != 4 && bits != 8)
+               
+       for (idx = 0; idx < nefxb; idx++)
+               if (1 << idx == bits)
+                       break;
+       
+       if (idx >= nefxb)
                return -EINVAL;
+
        spin_lock_irq(&emu->reg_lock);
        change = (nval[0] != emu->efx_voices_mask[0]) ||
                (nval[1] != emu->efx_voices_mask[1]);
@@ -1185,7 +1192,7 @@ static void fx8010_pb_trans_copy(snd_pcm_substream_t *substream,
        }
        snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos,
                                               (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2,
-                                              src, frames, tram_shift++);
+                                              src, frames, tram_shift);
        tram_pos -= frames;
        pcm->tram_pos = tram_pos;
        pcm->tram_shift = tram_shift;
index 994066c..90dcbe3 100644 (file)
@@ -229,7 +229,7 @@ static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry,
 
        snd_iprintf(buffer, "FX8010 Instruction List '%s'\n", emu->fx8010.name);
        snd_iprintf(buffer, "  Code dump      :\n");
-       for (pc = 0; pc < 512; pc++) {
+       for (pc = 0; pc < (emu->audigy ? 1024 : 512); pc++) {
                u32 low, high;
                        
                low = snd_emu10k1_efx_read(emu, pc * 2);
@@ -256,9 +256,13 @@ static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry,
 }
 
 #define TOTAL_SIZE_GPR         (0x100*4)
+#define A_TOTAL_SIZE_GPR       (0x200*4)
 #define TOTAL_SIZE_TANKMEM_DATA        (0xa0*4)
 #define TOTAL_SIZE_TANKMEM_ADDR (0xa0*4)
+#define A_TOTAL_SIZE_TANKMEM_DATA (0x100*4)
+#define A_TOTAL_SIZE_TANKMEM_ADDR (0x100*4)
 #define TOTAL_SIZE_CODE                (0x200*8)
+#define A_TOTAL_SIZE_CODE      (0x400*8)
 
 static long snd_emu10k1_fx8010_read(snd_info_entry_t *entry, void *file_private_data,
                                    struct file *file, char __user *buf,
@@ -267,12 +271,12 @@ static long snd_emu10k1_fx8010_read(snd_info_entry_t *entry, void *file_private_
        long size;
        emu10k1_t *emu = entry->private_data;
        unsigned int offset;
+       int tram_addr = 0;
        
        if (!strcmp(entry->name, "fx8010_tram_addr")) {
-               if (emu->audigy) return -EINVAL;
                offset = TANKMEMADDRREGBASE;
+               tram_addr = 1;
        } else if (!strcmp(entry->name, "fx8010_tram_data")) {
-               if (emu->audigy) return -EINVAL;
                offset = TANKMEMDATAREGBASE;
        } else if (!strcmp(entry->name, "fx8010_code")) {
                offset = emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
@@ -289,7 +293,11 @@ static long snd_emu10k1_fx8010_read(snd_info_entry_t *entry, void *file_private_
                if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL)
                        return -ENOMEM;
                for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++)
-                       tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
+                       if (tram_addr && emu->audigy) {
+                               tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11;
+                               tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
+                       } else 
+                               tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
                if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size))
                        res = -EFAULT;
                else {
@@ -316,35 +324,35 @@ int __devinit snd_emu10k1_proc_init(emu10k1_t * emu)
                entry->content = SNDRV_INFO_CONTENT_DATA;
                entry->private_data = emu;
                entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/;
-               entry->size = TOTAL_SIZE_GPR;
+               entry->size = emu->audigy ? A_TOTAL_SIZE_GPR : TOTAL_SIZE_GPR;
                entry->c.ops = &snd_emu10k1_proc_ops_fx8010;
        }
-       if (!emu->audigy && ! snd_card_proc_new(emu->card, "fx8010_tram_data", &entry)) {
+       if (! snd_card_proc_new(emu->card, "fx8010_tram_data", &entry)) {
                entry->content = SNDRV_INFO_CONTENT_DATA;
                entry->private_data = emu;
                entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/;
-               entry->size = TOTAL_SIZE_TANKMEM_DATA;
+               entry->size = emu->audigy ? A_TOTAL_SIZE_TANKMEM_DATA : TOTAL_SIZE_TANKMEM_DATA ;
                entry->c.ops = &snd_emu10k1_proc_ops_fx8010;
        }
-       if (!emu->audigy && ! snd_card_proc_new(emu->card, "fx8010_tram_addr", &entry)) {
+       if (! snd_card_proc_new(emu->card, "fx8010_tram_addr", &entry)) {
                entry->content = SNDRV_INFO_CONTENT_DATA;
                entry->private_data = emu;
                entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/;
-               entry->size = TOTAL_SIZE_TANKMEM_ADDR;
+               entry->size = emu->audigy ? A_TOTAL_SIZE_TANKMEM_ADDR : TOTAL_SIZE_TANKMEM_ADDR ;
                entry->c.ops = &snd_emu10k1_proc_ops_fx8010;
        }
        if (! snd_card_proc_new(emu->card, "fx8010_code", &entry)) {
                entry->content = SNDRV_INFO_CONTENT_DATA;
                entry->private_data = emu;
                entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/;
-               entry->size = TOTAL_SIZE_CODE;
+               entry->size = emu->audigy ? A_TOTAL_SIZE_CODE : TOTAL_SIZE_CODE;
                entry->c.ops = &snd_emu10k1_proc_ops_fx8010;
        }
        if (! snd_card_proc_new(emu->card, "fx8010_acode", &entry)) {
                entry->content = SNDRV_INFO_CONTENT_TEXT;
                entry->private_data = emu;
                entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/;
-               entry->c.text.read_size = 64*1024;
+               entry->c.text.read_size = 128*1024;
                entry->c.text.read = snd_emu10k1_proc_acode_read;
        }
        return 0;
index 8bf1ecf..746ebde 100644 (file)
@@ -32,7 +32,8 @@
                "{MidiMan M Audio,Delta 66},"\
                "{MidiMan M Audio,Delta 44},"\
                "{MidiMan M Audio,Audiophile 24/96},"\
-               "{Digigram,VX442},"
+               "{Digigram,VX442},"\
+               "{Lionstracs,Mediastation},"
 
 #define ICE1712_SUBDEVICE_DELTA1010    0x121430d6
 #define ICE1712_SUBDEVICE_DELTADIO2496 0x121431d6
@@ -42,6 +43,7 @@
 #define ICE1712_SUBDEVICE_DELTA410     0x121438d6
 #define ICE1712_SUBDEVICE_DELTA1010LT  0x12143bd6
 #define ICE1712_SUBDEVICE_VX442                0x12143cd6
+#define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100
 
 /* entry point */
 extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
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 */
index 2c2df37..4cde263 100644 (file)
@@ -53,7 +53,7 @@ struct mixart_uid
 
 struct mem_area {
        unsigned long phys;
-       unsigned long virt;
+       void __iomem *virt;
        struct resource *res;
 };
 
index ef6a655..b0a9ebf 100644 (file)
@@ -13,6 +13,11 @@ config SND_POWERMAC
        tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
        depends on SND && I2C && INPUT
        select SND_PCM
+       help
+         Say Y here to include support for the integrated sound device.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-powermac.
 
 endmenu
 
index 6629b6b..f24a916 100644 (file)
@@ -56,10 +56,11 @@ static int daca_init_client(pmac_keywest_t *i2c)
        unsigned short wdata = 0x00;
        /* SR: no swap, 1bit delay, 32-48kHz */
        /* GCFG: power amp inverted, DAC on */
-       if (snd_pmac_keywest_write_byte(i2c, DACA_REG_SR, 0x08) < 0 ||
-           snd_pmac_keywest_write_byte(i2c, DACA_REG_GCFG, 0x05) < 0)
+       if (i2c_smbus_write_byte_data(i2c->client, DACA_REG_SR, 0x08) < 0 ||
+           i2c_smbus_write_byte_data(i2c->client, DACA_REG_GCFG, 0x05) < 0)
                return -EINVAL;
-       return snd_pmac_keywest_write(i2c, DACA_REG_AVOL, 2, (unsigned char*)&wdata);
+       return i2c_smbus_write_block_data(i2c->client, DACA_REG_AVOL,
+                                         2, (unsigned char*)&wdata);
 }
 
 /*
@@ -81,9 +82,10 @@ static int daca_set_volume(pmac_daca_t *mix)
        else
                data[1] = mix->right_vol;
        data[1] |= mix->deemphasis ? 0x40 : 0;
-       if (snd_pmac_keywest_write(&mix->i2c, DACA_REG_AVOL, 2, data) < 0) {
-               snd_printk("failed to set volume \n");  
-               return -EINVAL; 
+       if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL,
+                                      2, data) < 0) {
+               snd_printk("failed to set volume \n");
+               return -EINVAL;
        }
        return 0;
 }
@@ -188,8 +190,8 @@ static int daca_put_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol
        change = mix->amp_on != ucontrol->value.integer.value[0];
        if (change) {
                mix->amp_on = ucontrol->value.integer.value[0];
-               snd_pmac_keywest_write_byte(&mix->i2c, DACA_REG_GCFG,
-                                           mix->amp_on ? 0x05 : 0x04);
+               i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
+                                         mix->amp_on ? 0x05 : 0x04);
        }
        return change;
 }
@@ -220,9 +222,9 @@ static snd_kcontrol_new_t daca_mixers[] = {
 static void daca_resume(pmac_t *chip)
 {
        pmac_daca_t *mix = chip->mixer_data;
-       snd_pmac_keywest_write_byte(&mix->i2c, DACA_REG_SR, 0x08);
-       snd_pmac_keywest_write_byte(&mix->i2c, DACA_REG_GCFG,
-                                   mix->amp_on ? 0x05 : 0x04);
+       i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_SR, 0x08);
+       i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
+                                 mix->amp_on ? 0x05 : 0x04);
        daca_set_volume(mix);
 }
 #endif /* CONFIG_PMAC_PBOOK */
index 934ead0..ed128c6 100644 (file)
@@ -1,6 +1,6 @@
 # ALSA USB drivers
 
-menu "ALSA USB devices"
+menu "USB devices"
        depends on SND!=n && USB!=n
 
 config SND_USB_AUDIO
@@ -9,7 +9,11 @@ config SND_USB_AUDIO
        select SND_RAWMIDI
        select SND_PCM
        help
-         Say 'Y' or 'M' to include support for USB audio and USB MIDI devices.
+         Say Y here to include support for USB audio and USB MIDI
+         devices.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-usb-audio.
 
 config SND_USB_USX2Y
        tristate "Tascam US-122, US-224 and US-428 USB driver"
@@ -18,8 +22,11 @@ config SND_USB_USX2Y
        select SND_RAWMIDI
        select SND_PCM
        help
-         Say 'Y' or 'M' to include support for Tascam USB Audio/MIDI 
+         Say Y here to include support for Tascam USB Audio/MIDI
          interfaces or controllers US-122, US-224 and US-428.
 
+         To compile this driver as a module, choose M here: the module
+         will be called snd-usb-usx2y.
+
 endmenu
 
index 96fd06e..7851da4 100644 (file)
@@ -715,9 +715,9 @@ void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver)
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
                snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
                if (ep->out && ep->out->urb)
-                       usb_unlink_urb(ep->out->urb);
+                       usb_kill_urb(ep->out->urb);
                if (ep->in && ep->in->urb)
-                       usb_unlink_urb(ep->in->urb);
+                       usb_kill_urb(ep->in->urb);
        }
 }
 
@@ -1161,7 +1161,7 @@ void snd_usbmidi_input_stop(struct list_head* p)
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
                snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
                if (ep->in)
-                       usb_unlink_urb(ep->in->urb);
+                       usb_kill_urb(ep->in->urb);
        }
 }
 
index f01947c..c69b4b0 100644 (file)
@@ -91,6 +91,14 @@ static struct usbmix_name_map extigy_map[] = {
        { 0 } /* terminator */
 };
 
+/* LineX FM Transmitter entry - needed to bypass controls bug */
+static struct usbmix_name_map linex_map[] = {
+       /* 1: IT pcm */
+       /* 2: OT Speaker */ 
+       { 3, "Master" }, /* FU: master volume - left / right / mute */
+       { 0 } /* terminator */
+};
+
 /* Section "justlink_map" below added by James Courtier-Dutton <James@superbug.demon.co.uk>
  * sourced from Maplin Electronics (http://www.maplin.co.uk), part number A56AK
  * Part has 2 connectors that act as a single output. (TOSLINK Optical for digital out, and 3.5mm Jack for Analogue out.)
@@ -120,6 +128,7 @@ static struct usbmix_name_map justlink_map[] = {
 
 static struct usbmix_ctl_map usbmix_ctl_maps[] = {
        { 0x41e, 0x3000, extigy_map, 1 },
+       { 0x8bb, 0x2702, linex_map, 1 },
        { 0xc45, 0x1158, justlink_map, 0 },
        { 0 } /* terminator */
 };
index 44a7381..82ecbf6 100644 (file)
@@ -1,6 +1,10 @@
 /*
  * usbus428.c - ALSA USB US-428 Driver
  *
+2004-09-20 Karsten Wiese
+       Version 0.7.3:
+       Use usb_kill_urb() instead of deprecated (kernel 2.6.9) usb_unlink_urb().
+
 2004-07-13 Karsten Wiese
        Version 0.7.1:
        Don't sleep in START/STOP callbacks anymore.
 
 
 MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
-MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.7.2");
+MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.7.3");
 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_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS".");
-module_param_array(id, charp, boot_devs, 0444);
+module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS".");
-module_param_array(enable, bool, boot_devs, 0444);
+module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS".");
 
 
@@ -277,7 +280,7 @@ 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_kill_urb(S->urb[i]);
                        usb_free_urb(S->urb[i]);
                        S->urb[i] = NULL;
                }
@@ -408,7 +411,7 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr)
                usX2Y->chip.shutdown = 1;
                usX2Y->chip_status = USX2Y_STAT_CHIP_HUP;
                usX2Y_unlinkSeq(&usX2Y->AS04);
-               usb_unlink_urb(usX2Y->In04urb);
+               usb_kill_urb(usX2Y->In04urb);
                snd_card_disconnect((snd_card_t*)ptr);
                /* release the midi resources */
                list_for_each(p, &usX2Y->chip.midi_list) {
index d860c73..e32673e 100644 (file)
@@ -656,7 +656,7 @@ static int usX2Y_rate_set(usX2Ydev_t *usX2Y, int rate)
                if (us) {
                        us->submitted = 2*NOOF_SETRATE_URBS;
                        for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
-                               usb_unlink_urb(us->urb[i]);
+                               usb_kill_urb(us->urb[i]);
                                usb_free_urb(us->urb[i]);
                        }
                        usX2Y->US04 = NULL;
@@ -671,7 +671,7 @@ static int usX2Y_rate_set(usX2Ydev_t *usX2Y, int rate)
 
 static int usX2Y_format_set(usX2Ydev_t *usX2Y, snd_pcm_format_t format)
 {
-       int alternate, unlink_err, err;
+       int alternate, err;
        struct list_head* p;
        if (format == SNDRV_PCM_FORMAT_S24_3LE) {
                alternate = 2;
@@ -683,15 +683,13 @@ static int usX2Y_format_set(usX2Ydev_t *usX2Y, snd_pcm_format_t format)
        list_for_each(p, &usX2Y->chip.midi_list) {
                snd_usbmidi_input_stop(p);
        }
-       unlink_err = usb_unlink_urb(usX2Y->In04urb);
+       usb_kill_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);
-       }
+       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);
        }
@@ -824,20 +822,20 @@ static int snd_usX2Y_pcm_prepare(snd_pcm_substream_t *substream)
                        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;
+                       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;
index 965759f..f269a5f 100644 (file)
@@ -3,7 +3,12 @@ obj-y := initramfs_data.o
 
 hostprogs-y  := gen_init_cpio
 
-clean-files := initramfs_data.cpio.gz
+clean-files := initramfs_data.cpio.gz initramfs_list
+
+# If you want a different list of files in the initramfs_data.cpio
+# then you can either overwrite the cpio_list in this directory
+# or set INITRAMFS_LIST to another filename.
+INITRAMFS_LIST := $(obj)/initramfs_list
 
 # initramfs_data.o contains the initramfs_data.cpio.gz image.
 # The image is included using .incbin, a dependency which is not
@@ -18,10 +23,17 @@ $(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio.gz FORCE
 # Commented out for now
 # initramfs-y := $(obj)/root/hello
 
+filechk_initramfs_list = $(CONFIG_SHELL) \
+ $(srctree)/scripts/gen_initramfs_list.sh $(CONFIG_INITRAMFS_SOURCE)
+                          
+$(obj)/initramfs_list: FORCE
+       $(call filechk,initramfs_list)
+
 quiet_cmd_cpio = CPIO    $@
-      cmd_cpio = ./$< > $@
+      cmd_cpio = ./$< $(obj)/initramfs_list > $@
 
-$(obj)/initramfs_data.cpio: $(obj)/gen_init_cpio $(initramfs-y) FORCE
+$(obj)/initramfs_data.cpio: $(obj)/gen_init_cpio \
+                            $(initramfs-y) $(obj)/initramfs_list FORCE
        $(call if_changed,cpio)
 
 targets += initramfs_data.cpio
index bf2d1fd..7672fbb 100644 (file)
@@ -6,10 +6,21 @@
 #include <unistd.h>
 #include <time.h>
 #include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+
+#define xstr(s) #s
+#define str(s) xstr(s)
 
 static unsigned int offset;
 static unsigned int ino = 721;
 
+struct file_type {
+       const char *type;
+       int (*handler)(const char *line);
+};
+
 static void push_string(const char *name)
 {
        unsigned int name_len = strlen(name) + 1;
@@ -80,7 +91,7 @@ static void cpio_trailer(void)
        }
 }
 
-static void cpio_mkdir(const char *name, unsigned int mode,
+static int cpio_mkdir(const char *name, unsigned int mode,
                       uid_t uid, gid_t gid)
 {
        char s[256];
@@ -104,10 +115,28 @@ static void cpio_mkdir(const char *name, unsigned int mode,
                0);                     /* chksum */
        push_hdr(s);
        push_rest(name);
+       return 0;
+}
+
+static int cpio_mkdir_line(const char *line)
+{
+       char name[PATH_MAX + 1];
+       unsigned int mode;
+       int uid;
+       int gid;
+       int rc = -1;
+
+       if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
+               fprintf(stderr, "Unrecognized dir format '%s'", line);
+               goto fail;
+       }
+       rc = cpio_mkdir(name, mode, uid, gid);
+ fail:
+       return rc;
 }
 
-static void cpio_mknod(const char *name, unsigned int mode,
-                      uid_t uid, gid_t gid, int dev_type,
+static int cpio_mknod(const char *name, unsigned int mode,
+                      uid_t uid, gid_t gid, char dev_type,
                       unsigned int maj, unsigned int min)
 {
        char s[256];
@@ -136,43 +165,66 @@ static void cpio_mknod(const char *name, unsigned int mode,
                0);                     /* chksum */
        push_hdr(s);
        push_rest(name);
+       return 0;
+}
+
+static int cpio_mknod_line(const char *line)
+{
+       char name[PATH_MAX + 1];
+       unsigned int mode;
+       int uid;
+       int gid;
+       char dev_type;
+       unsigned int maj;
+       unsigned int min;
+       int rc = -1;
+
+       if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
+                        name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
+               fprintf(stderr, "Unrecognized nod format '%s'", line);
+               goto fail;
+       }
+       rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
+ fail:
+       return rc;
 }
 
 /* Not marked static to keep the compiler quiet, as no one uses this yet... */
-void cpio_mkfile(const char *filename, const char *location,
+static int cpio_mkfile(const char *name, const char *location,
                        unsigned int mode, uid_t uid, gid_t gid)
 {
        char s[256];
-       char *filebuf;
+       char *filebuf = NULL;
        struct stat buf;
-       int file;
+       int file = -1;
        int retval;
        int i;
+       int rc = -1;
 
        mode |= S_IFREG;
 
-       retval = stat (filename, &buf);
+       retval = stat (location, &buf);
        if (retval) {
-               fprintf (stderr, "Filename %s could not be located\n", filename);
+               fprintf (stderr, "File %s could not be located\n", location);
                goto error;
        }
 
-       file = open (filename, O_RDONLY);
+       file = open (location, O_RDONLY);
        if (file < 0) {
-               fprintf (stderr, "Filename %s could not be opened for reading\n", filename);
+               fprintf (stderr, "File %s could not be opened for reading\n", location);
                goto error;
        }
 
        filebuf = malloc(buf.st_size);
        if (!filebuf) {
                fprintf (stderr, "out of memory\n");
-               goto error_close;
+               goto error;
        }
 
        retval = read (file, filebuf, buf.st_size);
        if (retval < 0) {
-               fprintf (stderr, "Can not read %s file\n", filename);
-               goto error_free;
+               fprintf (stderr, "Can not read %s file\n", location);
+               goto error;
        }
 
        sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
@@ -189,40 +241,164 @@ void cpio_mkfile(const char *filename, const char *location,
                1,                      /* minor */
                0,                      /* rmajor */
                0,                      /* rminor */
-               (unsigned)strlen(location) + 1,/* namesize */
+               (unsigned)strlen(name) + 1,/* namesize */
                0);                     /* chksum */
        push_hdr(s);
-       push_string(location);
+       push_string(name);
        push_pad();
 
        for (i = 0; i < buf.st_size; ++i)
                fputc(filebuf[i], stdout);
        offset += buf.st_size;
-       close(file);
-       free(filebuf);
        push_pad();
-       return;
+       rc = 0;
        
-error_free:
-       free(filebuf);
-error_close:
-       close(file);
 error:
-       exit(-1);
+       if (filebuf) free(filebuf);
+       if (file >= 0) close(file);
+       return rc;
 }
 
-int main (int argc, char *argv[])
+static int cpio_mkfile_line(const char *line)
 {
-       cpio_mkdir("/dev", 0755, 0, 0);
-       cpio_mknod("/dev/console", 0600, 0, 0, 'c', 5, 1);
-       cpio_mkdir("/root", 0700, 0, 0);
-       cpio_trailer();
+       char name[PATH_MAX + 1];
+       char location[PATH_MAX + 1];
+       unsigned int mode;
+       int uid;
+       int gid;
+       int rc = -1;
 
-       exit(0);
+       if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, location, &mode, &uid, &gid)) {
+               fprintf(stderr, "Unrecognized file format '%s'", line);
+               goto fail;
+       }
+       rc = cpio_mkfile(name, location, mode, uid, gid);
+ fail:
+       return rc;
+}
 
-       /* silence compiler warnings */
-       return 0;
-       (void) argc;
-       (void) argv;
+void usage(const char *prog)
+{
+       fprintf(stderr, "Usage:\n"
+               "\t%s <cpio_list>\n"
+               "\n"
+               "<cpio_list> is a file containing newline separated entries that\n"
+               "describe the files to be included in the initramfs archive:\n"
+               "\n"
+               "# a comment\n"
+               "file <name> <location> <mode> <uid> <gid> \n"
+               "dir <name> <mode> <uid> <gid>\n"
+               "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
+               "\n"
+               "<name>      name of the file/dir/nod in the archive\n"
+               "<location>  location of the file in the current filesystem\n"
+               "<mode>      mode/permissions of the file\n"
+               "<uid>       user id (0=root)\n"
+               "<gid>       group id (0=root)\n"
+               "<dev_type>  device type (b=block, c=character)\n"
+               "<maj>       major number of nod\n"
+               "<min>       minor number of nod\n"
+               "\n"
+               "example:\n"
+               "# A simple initramfs\n"
+               "dir /dev 0755 0 0\n"
+               "nod /dev/console 0600 0 0 c 5 1\n"
+               "dir /root 0700 0 0\n"
+               "dir /sbin 0755 0 0\n"
+               "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n",
+               prog);
 }
 
+struct file_type file_type_table[] = {
+       {
+               .type    = "file",
+               .handler = cpio_mkfile_line,
+       }, {
+               .type    = "nod",
+               .handler = cpio_mknod_line,
+       }, {
+               .type    = "dir",
+               .handler = cpio_mkdir_line,
+       }, {
+               .type    = NULL,
+               .handler = NULL,
+       }
+};
+
+#define LINE_SIZE (2 * PATH_MAX + 50)
+
+int main (int argc, char *argv[])
+{
+       FILE *cpio_list;
+       char line[LINE_SIZE];
+       char *args, *type;
+       int ec = 0;
+       int line_nr = 0;
+
+       if (2 != argc) {
+               usage(argv[0]);
+               exit(1);
+       }
+
+       if (! (cpio_list = fopen(argv[1], "r"))) {
+               fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
+                       argv[1], strerror(errno));
+               usage(argv[0]);
+               exit(1);
+       }
+
+       while (fgets(line, LINE_SIZE, cpio_list)) {
+               int type_idx;
+               size_t slen = strlen(line);
+
+               line_nr++;
+
+               if ('#' == *line) {
+                       /* comment - skip to next line */
+                       continue;
+               }
+
+               if (! (type = strtok(line, " \t"))) {
+                       fprintf(stderr,
+                               "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
+                               line_nr, line);
+                       ec = -1;
+               }
+
+               if ('\n' == *type) {
+                       /* a blank line */
+                       continue;
+               }
+
+               if (slen == strlen(type)) {
+                       /* must be an empty line */
+                       continue;
+               }
+
+               if (! (args = strtok(NULL, "\n"))) {
+                       fprintf(stderr,
+                               "ERROR: incorrect format, newline required line %d: '%s'\n",
+                               line_nr, line);
+                       ec = -1;
+               }
+
+               for (type_idx = 0; file_type_table[type_idx].type; type_idx++) {
+                       int rc;
+                       if (! strcmp(line, file_type_table[type_idx].type)) {
+                               if ((rc = file_type_table[type_idx].handler(args))) {
+                                       ec = rc;
+                                       fprintf(stderr, " line %d\n", line_nr);
+                               }
+                               break;
+                       }
+               }
+
+               if (NULL == file_type_table[type_idx].type) {
+                       fprintf(stderr, "unknown file type line %d: '%s'\n",
+                               line_nr, line);
+               }
+       }
+       cpio_trailer();
+
+       exit(ec);
+}